- added myself to copyright on files i remember adding large contributions for over...
[openocd.git] / src / jtag / parport.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "replacements.h"
28
29 #include "jtag.h"
30 #include "bitbang.h"
31
32 /* system includes */
33 /* -ino: 060521-1036 */
34 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
35
36 #include <sys/types.h>
37 #include <machine/sysarch.h>
38 #include <machine/cpufunc.h>
39 #define ioperm(startport,length,enable)\
40 i386_set_ioperm((startport), (length), (enable))
41
42 #else
43
44 #ifdef _WIN32
45 #include "errno.h"
46 #endif /* _WIN32 */
47
48 #endif /* __FreeBSD__ */
49
50 #include <string.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53
54 #if PARPORT_USE_PPDEV == 1
55 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
56 #include <dev/ppbus/ppi.h>
57 #include <dev/ppbus/ppbconf.h>
58 #define PPRSTATUS PPIGSTATUS
59 #define PPWDATA PPISDATA
60 #else
61 #include <linux/parport.h>
62 #include <linux/ppdev.h>
63 #endif
64 #include <fcntl.h>
65 #include <sys/ioctl.h>
66 #else /* not PARPORT_USE_PPDEV */
67 #ifndef _WIN32
68 #include <sys/io.h>
69 #endif
70 #endif
71
72 #if PARPORT_USE_GIVEIO == 1
73 #if IS_CYGWIN == 1
74 #include <windows.h>
75 #include <errno.h>
76 #endif
77 #endif
78
79 #include "log.h"
80
81 /* parallel port cable description
82 */
83 typedef struct cable_s
84 {
85 char* name;
86 u8 TDO_MASK; /* status port bit containing current TDO value */
87 u8 TRST_MASK; /* data port bit for TRST */
88 u8 TMS_MASK; /* data port bit for TMS */
89 u8 TCK_MASK; /* data port bit for TCK */
90 u8 TDI_MASK; /* data port bit for TDI */
91 u8 SRST_MASK; /* data port bit for SRST */
92 u8 OUTPUT_INVERT; /* data port bits that should be inverted */
93 u8 INPUT_INVERT; /* status port that should be inverted */
94 u8 PORT_INIT; /* initialize data port with this value */
95 u8 PORT_EXIT; /* de-initialize data port with this value */
96 u8 LED_MASK; /* data port bit for LED */
97 } cable_t;
98
99 cable_t cables[] =
100 {
101 /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
102 { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
103 { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
104 { "wiggler_ntrst_inverted",
105 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
106 { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
107 { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 },
108 { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
109 { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 },
110 { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
111 { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 },
112 { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 },
113 /* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows:
114 HARD TCK - Target TCK
115 HARD TMS - Target TMS
116 HARD TDI - Target TDI
117 HARD TDO - Target TDO
118 SOFT TCK - Target TRST
119 SOFT TDI - Target SRST
120 */
121 { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 },
122 { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
123 };
124
125 /* configuration */
126 char* parport_cable = NULL;
127 u16 parport_port;
128 static int parport_exit = 0;
129
130 /* interface variables
131 */
132 static cable_t* cable;
133 static u8 dataport_value = 0x0;
134
135 #if PARPORT_USE_PPDEV == 1
136 static int device_handle;
137 #else
138 static unsigned long dataport;
139 static unsigned long statusport;
140 #endif
141
142 /* low level command set
143 */
144 int parport_read(void);
145 void parport_write(int tck, int tms, int tdi);
146 void parport_reset(int trst, int srst);
147 void parport_led(int on);
148
149 int parport_speed(int speed);
150 int parport_register_commands(struct command_context_s *cmd_ctx);
151 int parport_init(void);
152 int parport_quit(void);
153
154 /* interface commands */
155 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
156 int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
157 int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
158
159 jtag_interface_t parport_interface =
160 {
161 .name = "parport",
162
163 .execute_queue = bitbang_execute_queue,
164
165 .speed = parport_speed,
166 .register_commands = parport_register_commands,
167 .init = parport_init,
168 .quit = parport_quit,
169 };
170
171 bitbang_interface_t parport_bitbang =
172 {
173 .read = parport_read,
174 .write = parport_write,
175 .reset = parport_reset,
176 .blink = parport_led
177 };
178
179 int parport_read(void)
180 {
181 int data = 0;
182
183 #if PARPORT_USE_PPDEV == 1
184 ioctl(device_handle, PPRSTATUS, & data);
185 #else
186 data = inb(statusport);
187 #endif
188
189 if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
190 return 1;
191 else
192 return 0;
193 }
194
195 static __inline__ void parport_write_data(void)
196 {
197 u8 output;
198 output = dataport_value ^ cable->OUTPUT_INVERT;
199
200 #if PARPORT_USE_PPDEV == 1
201 ioctl(device_handle, PPWDATA, &output);
202 #else
203 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
204 outb(dataport, output);
205 #else
206 outb(output, dataport);
207 #endif
208 #endif
209 }
210
211 void parport_write(int tck, int tms, int tdi)
212 {
213 int i = jtag_speed + 1;
214
215 if (tck)
216 dataport_value |= cable->TCK_MASK;
217 else
218 dataport_value &= ~cable->TCK_MASK;
219
220 if (tms)
221 dataport_value |= cable->TMS_MASK;
222 else
223 dataport_value &= ~cable->TMS_MASK;
224
225 if (tdi)
226 dataport_value |= cable->TDI_MASK;
227 else
228 dataport_value &= ~cable->TDI_MASK;
229
230 while (i-- > 0)
231 parport_write_data();
232 }
233
234 /* (1) assert or (0) deassert reset lines */
235 void parport_reset(int trst, int srst)
236 {
237 LOG_DEBUG("trst: %i, srst: %i", trst, srst);
238
239 if (trst == 0)
240 dataport_value |= cable->TRST_MASK;
241 else if (trst == 1)
242 dataport_value &= ~cable->TRST_MASK;
243
244 if (srst == 0)
245 dataport_value |= cable->SRST_MASK;
246 else if (srst == 1)
247 dataport_value &= ~cable->SRST_MASK;
248
249 parport_write_data();
250 }
251
252 /* turn LED on parport adapter on (1) or off (0) */
253 void parport_led(int on)
254 {
255 if (on)
256 dataport_value |= cable->LED_MASK;
257 else
258 dataport_value &= ~cable->LED_MASK;
259
260 parport_write_data();
261 }
262
263 int parport_speed(int speed)
264 {
265 return ERROR_OK;
266 }
267
268 int parport_register_commands(struct command_context_s *cmd_ctx)
269 {
270 register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
271 COMMAND_CONFIG, NULL);
272 register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
273 COMMAND_CONFIG, NULL);
274 register_command(cmd_ctx, NULL, "parport_write_on_exit", parport_handle_write_on_exit_command,
275 COMMAND_CONFIG, NULL);
276
277 return ERROR_OK;
278 }
279
280 #if PARPORT_USE_GIVEIO == 1
281 int parport_get_giveio_access(void)
282 {
283 HANDLE h;
284 OSVERSIONINFO version;
285
286 version.dwOSVersionInfoSize = sizeof version;
287 if (!GetVersionEx( &version )) {
288 errno = EINVAL;
289 return -1;
290 }
291 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
292 return 0;
293
294 h = CreateFile( "\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
295 if (h == INVALID_HANDLE_VALUE) {
296 errno = ENODEV;
297 return -1;
298 }
299
300 CloseHandle( h );
301
302 return 0;
303 }
304 #endif
305
306 int parport_init(void)
307 {
308 cable_t *cur_cable;
309 #if PARPORT_USE_PPDEV == 1
310 char buffer[256];
311 int i = 0;
312 #endif
313
314 cur_cable = cables;
315
316 if ((parport_cable == NULL) || (parport_cable[0] == 0))
317 {
318 parport_cable = "wiggler";
319 LOG_WARNING("No parport cable specified, using default 'wiggler'");
320 }
321
322 while (cur_cable->name)
323 {
324 if (strcmp(cur_cable->name, parport_cable) == 0)
325 {
326 cable = cur_cable;
327 break;
328 }
329 cur_cable++;
330 }
331
332 if (!cable)
333 {
334 LOG_ERROR("No matching cable found for %s", parport_cable);
335 return ERROR_JTAG_INIT_FAILED;
336 }
337
338 dataport_value = cable->PORT_INIT;
339
340 #if PARPORT_USE_PPDEV == 1
341 if (device_handle > 0)
342 {
343 LOG_ERROR("device is already opened");
344 return ERROR_JTAG_INIT_FAILED;
345 }
346
347 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
348 LOG_DEBUG("opening /dev/ppi%d...", parport_port);
349
350 snprintf(buffer, 256, "/dev/ppi%d", parport_port);
351 device_handle = open(buffer, O_WRONLY);
352 #else /* not __FreeBSD__, __FreeBSD_kernel__ */
353 LOG_DEBUG("opening /dev/parport%d...", parport_port);
354
355 snprintf(buffer, 256, "/dev/parport%d", parport_port);
356 device_handle = open(buffer, O_WRONLY);
357 #endif /* __FreeBSD__, __FreeBSD_kernel__ */
358
359 if (device_handle < 0)
360 {
361 LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
362 return ERROR_JTAG_INIT_FAILED;
363 }
364
365 LOG_DEBUG("...open");
366
367 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
368 i=ioctl(device_handle, PPCLAIM);
369 if (i<0)
370 {
371 LOG_ERROR("cannot claim device");
372 return ERROR_JTAG_INIT_FAILED;
373 }
374
375 i = PARPORT_MODE_COMPAT;
376 i= ioctl(device_handle, PPSETMODE, & i);
377 if (i<0)
378 {
379 LOG_ERROR(" cannot set compatible mode to device");
380 return ERROR_JTAG_INIT_FAILED;
381 }
382
383 i = IEEE1284_MODE_COMPAT;
384 i = ioctl(device_handle, PPNEGOT, & i);
385 if (i<0)
386 {
387 LOG_ERROR("cannot set compatible 1284 mode to device");
388 return ERROR_JTAG_INIT_FAILED;
389 }
390 #endif /* not __FreeBSD__, __FreeBSD_kernel__ */
391
392 #else /* not PARPORT_USE_PPDEV */
393 if (parport_port == 0)
394 {
395 parport_port = 0x378;
396 LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
397 }
398
399 dataport = parport_port;
400 statusport = parport_port + 1;
401
402 LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
403 #if PARPORT_USE_GIVEIO == 1
404 if (parport_get_giveio_access() != 0)
405 #else /* PARPORT_USE_GIVEIO */
406 if (ioperm(dataport, 3, 1) != 0)
407 #endif /* PARPORT_USE_GIVEIO */
408 {
409 LOG_ERROR("missing privileges for direct i/o");
410 return ERROR_JTAG_INIT_FAILED;
411 }
412 LOG_DEBUG("...privileges granted");
413
414 /* make sure parallel port is in right mode (clear tristate and interrupt */
415 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
416 outb(parport_port + 2, 0x0);
417 #else
418 outb(0x0, parport_port + 2);
419 #endif
420
421 #endif /* PARPORT_USE_PPDEV */
422
423 parport_reset(0, 0);
424 parport_write(0, 0, 0);
425 parport_led(1);
426
427 bitbang_interface = &parport_bitbang;
428
429 return ERROR_OK;
430 }
431
432 int parport_quit(void)
433 {
434 parport_led(0);
435
436 if (parport_exit)
437 {
438 dataport_value = cable->PORT_EXIT;
439 parport_write_data();
440 }
441
442 if (parport_cable)
443 {
444 free(parport_cable);
445 parport_cable = NULL;
446 }
447
448 return ERROR_OK;
449 }
450
451 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
452 {
453 if (argc == 0)
454 return ERROR_OK;
455
456 /* only if the port wasn't overwritten by cmdline */
457 if (parport_port == 0)
458 parport_port = strtoul(args[0], NULL, 0);
459
460 return ERROR_OK;
461 }
462
463 int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
464 {
465 if (argc == 0)
466 return ERROR_OK;
467
468 /* only if the cable name wasn't overwritten by cmdline */
469 if (parport_cable == 0)
470 {
471 parport_cable = malloc(strlen(args[0]) + sizeof(char));
472 strcpy(parport_cable, args[0]);
473 }
474
475 return ERROR_OK;
476 }
477
478 int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
479 {
480 if (argc != 1)
481 {
482 command_print(cmd_ctx, "usage: parport_write_on_exit <on|off>");
483 return ERROR_OK;
484 }
485
486 if (strcmp(args[0], "on") == 0)
487 parport_exit = 1;
488 else if (strcmp(args[0], "off") == 0)
489 parport_exit = 0;
490
491 return ERROR_OK;
492 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)