d4d9b22d6373a9ca4cbd6310cbcf2295228d5f15
[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 "interface.h"
28 #include "bitbang.h"
29
30 /* -ino: 060521-1036 */
31 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
32 #include <machine/sysarch.h>
33 #include <machine/cpufunc.h>
34 #define ioperm(startport,length,enable)\
35 i386_set_ioperm((startport), (length), (enable))
36 #endif /* __FreeBSD__ */
37
38 #if PARPORT_USE_PPDEV == 1
39 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
40 #include <dev/ppbus/ppi.h>
41 #include <dev/ppbus/ppbconf.h>
42 #define PPRSTATUS PPIGSTATUS
43 #define PPWDATA PPISDATA
44 #else
45 #include <linux/parport.h>
46 #include <linux/ppdev.h>
47 #endif
48 #include <sys/ioctl.h>
49 #else /* not PARPORT_USE_PPDEV */
50 #ifndef _WIN32
51 #include <sys/io.h>
52 #endif
53 #endif
54
55 #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1
56 #include <windows.h>
57 #endif
58
59
60 /* parallel port cable description
61 */
62 typedef struct cable_s
63 {
64 char* name;
65 uint8_t TDO_MASK; /* status port bit containing current TDO value */
66 uint8_t TRST_MASK; /* data port bit for TRST */
67 uint8_t TMS_MASK; /* data port bit for TMS */
68 uint8_t TCK_MASK; /* data port bit for TCK */
69 uint8_t TDI_MASK; /* data port bit for TDI */
70 uint8_t SRST_MASK; /* data port bit for SRST */
71 uint8_t OUTPUT_INVERT; /* data port bits that should be inverted */
72 uint8_t INPUT_INVERT; /* status port that should be inverted */
73 uint8_t PORT_INIT; /* initialize data port with this value */
74 uint8_t PORT_EXIT; /* de-initialize data port with this value */
75 uint8_t LED_MASK; /* data port bit for LED */
76 } cable_t;
77
78 static cable_t cables[] =
79 {
80 /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
81 { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
82 { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
83 { "wiggler_ntrst_inverted",
84 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
85 { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
86 { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 },
87 { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
88 { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 },
89 { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
90 { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 },
91 { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 },
92 /* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows:
93 HARD TCK - Target TCK
94 HARD TMS - Target TMS
95 HARD TDI - Target TDI
96 HARD TDO - Target TDO
97 SOFT TCK - Target TRST
98 SOFT TDI - Target SRST
99 */
100 { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 },
101 { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
102 };
103
104 /* configuration */
105 static char* parport_cable = NULL;
106 static uint16_t parport_port;
107 static int parport_exit = 0;
108 static uint32_t parport_toggling_time_ns = 1000;
109 static int wait_states;
110
111 /* interface variables
112 */
113 static cable_t* cable;
114 static uint8_t dataport_value = 0x0;
115
116 #if PARPORT_USE_PPDEV == 1
117 static int device_handle;
118 #else
119 static unsigned long dataport;
120 static unsigned long statusport;
121 #endif
122
123 static int parport_read(void)
124 {
125 int data = 0;
126
127 #if PARPORT_USE_PPDEV == 1
128 ioctl(device_handle, PPRSTATUS, & data);
129 #else
130 data = inb(statusport);
131 #endif
132
133 if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
134 return 1;
135 else
136 return 0;
137 }
138
139 static __inline__ void parport_write_data(void)
140 {
141 uint8_t output;
142 output = dataport_value ^ cable->OUTPUT_INVERT;
143
144 #if PARPORT_USE_PPDEV == 1
145 ioctl(device_handle, PPWDATA, &output);
146 #else
147 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
148 outb(dataport, output);
149 #else
150 outb(output, dataport);
151 #endif
152 #endif
153 }
154
155 static void parport_write(int tck, int tms, int tdi)
156 {
157 int i = wait_states + 1;
158
159 if (tck)
160 dataport_value |= cable->TCK_MASK;
161 else
162 dataport_value &= ~cable->TCK_MASK;
163
164 if (tms)
165 dataport_value |= cable->TMS_MASK;
166 else
167 dataport_value &= ~cable->TMS_MASK;
168
169 if (tdi)
170 dataport_value |= cable->TDI_MASK;
171 else
172 dataport_value &= ~cable->TDI_MASK;
173
174 while (i-- > 0)
175 parport_write_data();
176 }
177
178 /* (1) assert or (0) deassert reset lines */
179 static void parport_reset(int trst, int srst)
180 {
181 LOG_DEBUG("trst: %i, srst: %i", trst, srst);
182
183 if (trst == 0)
184 dataport_value |= cable->TRST_MASK;
185 else if (trst == 1)
186 dataport_value &= ~cable->TRST_MASK;
187
188 if (srst == 0)
189 dataport_value |= cable->SRST_MASK;
190 else if (srst == 1)
191 dataport_value &= ~cable->SRST_MASK;
192
193 parport_write_data();
194 }
195
196 /* turn LED on parport adapter on (1) or off (0) */
197 static void parport_led(int on)
198 {
199 if (on)
200 dataport_value |= cable->LED_MASK;
201 else
202 dataport_value &= ~cable->LED_MASK;
203
204 parport_write_data();
205 }
206
207 static int parport_speed(int speed)
208 {
209 wait_states = speed;
210 return ERROR_OK;
211 }
212
213 static int parport_khz(int khz, int* jtag_speed)
214 {
215 if (khz == 0) {
216 LOG_DEBUG("RCLK not supported");
217 return ERROR_FAIL;
218 }
219
220 *jtag_speed = 499999 / (khz * parport_toggling_time_ns);
221 return ERROR_OK;
222 }
223
224 static int parport_speed_div(int speed, int* khz)
225 {
226 uint32_t denominator = (speed + 1) * parport_toggling_time_ns;
227
228 *khz = (499999 + denominator) / denominator;
229 return ERROR_OK;
230 }
231
232 #if PARPORT_USE_GIVEIO == 1
233 static int parport_get_giveio_access(void)
234 {
235 HANDLE h;
236 OSVERSIONINFO version;
237
238 version.dwOSVersionInfoSize = sizeof version;
239 if (!GetVersionEx(&version)) {
240 errno = EINVAL;
241 return -1;
242 }
243 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
244 return 0;
245
246 h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
247 if (h == INVALID_HANDLE_VALUE) {
248 errno = ENODEV;
249 return -1;
250 }
251
252 CloseHandle(h);
253
254 return 0;
255 }
256 #endif
257
258 static struct bitbang_interface parport_bitbang = {
259 .read = &parport_read,
260 .write = &parport_write,
261 .reset = &parport_reset,
262 .blink = &parport_led,
263 };
264
265 static int parport_init(void)
266 {
267 cable_t *cur_cable;
268 #if PARPORT_USE_PPDEV == 1
269 char buffer[256];
270 int i = 0;
271 #endif
272
273 cur_cable = cables;
274
275 if ((parport_cable == NULL) || (parport_cable[0] == 0))
276 {
277 parport_cable = "wiggler";
278 LOG_WARNING("No parport cable specified, using default 'wiggler'");
279 }
280
281 while (cur_cable->name)
282 {
283 if (strcmp(cur_cable->name, parport_cable) == 0)
284 {
285 cable = cur_cable;
286 break;
287 }
288 cur_cable++;
289 }
290
291 if (!cable)
292 {
293 LOG_ERROR("No matching cable found for %s", parport_cable);
294 return ERROR_JTAG_INIT_FAILED;
295 }
296
297 dataport_value = cable->PORT_INIT;
298
299 #if PARPORT_USE_PPDEV == 1
300 if (device_handle > 0)
301 {
302 LOG_ERROR("device is already opened");
303 return ERROR_JTAG_INIT_FAILED;
304 }
305
306 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
307 LOG_DEBUG("opening /dev/ppi%d...", parport_port);
308
309 snprintf(buffer, 256, "/dev/ppi%d", parport_port);
310 device_handle = open(buffer, O_WRONLY);
311 #else /* not __FreeBSD__, __FreeBSD_kernel__ */
312 LOG_DEBUG("opening /dev/parport%d...", parport_port);
313
314 snprintf(buffer, 256, "/dev/parport%d", parport_port);
315 device_handle = open(buffer, O_WRONLY);
316 #endif /* __FreeBSD__, __FreeBSD_kernel__ */
317
318 if (device_handle < 0)
319 {
320 int err = errno;
321 LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err);
322 return ERROR_JTAG_INIT_FAILED;
323 }
324
325 LOG_DEBUG("...open");
326
327 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
328 i = ioctl(device_handle, PPCLAIM);
329 if (i < 0)
330 {
331 LOG_ERROR("cannot claim device");
332 return ERROR_JTAG_INIT_FAILED;
333 }
334
335 i = PARPORT_MODE_COMPAT;
336 i= ioctl(device_handle, PPSETMODE, & i);
337 if (i < 0)
338 {
339 LOG_ERROR(" cannot set compatible mode to device");
340 return ERROR_JTAG_INIT_FAILED;
341 }
342
343 i = IEEE1284_MODE_COMPAT;
344 i = ioctl(device_handle, PPNEGOT, & i);
345 if (i < 0)
346 {
347 LOG_ERROR("cannot set compatible 1284 mode to device");
348 return ERROR_JTAG_INIT_FAILED;
349 }
350 #endif /* not __FreeBSD__, __FreeBSD_kernel__ */
351
352 #else /* not PARPORT_USE_PPDEV */
353 if (parport_port == 0)
354 {
355 parport_port = 0x378;
356 LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
357 }
358
359 dataport = parport_port;
360 statusport = parport_port + 1;
361
362 LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
363 #if PARPORT_USE_GIVEIO == 1
364 if (parport_get_giveio_access() != 0)
365 #else /* PARPORT_USE_GIVEIO */
366 if (ioperm(dataport, 3, 1) != 0)
367 #endif /* PARPORT_USE_GIVEIO */
368 {
369 LOG_ERROR("missing privileges for direct i/o");
370 return ERROR_JTAG_INIT_FAILED;
371 }
372 LOG_DEBUG("...privileges granted");
373
374 /* make sure parallel port is in right mode (clear tristate and interrupt */
375 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
376 outb(parport_port + 2, 0x0);
377 #else
378 outb(0x0, parport_port + 2);
379 #endif
380
381 #endif /* PARPORT_USE_PPDEV */
382
383 parport_reset(0, 0);
384 parport_write(0, 0, 0);
385 parport_led(1);
386
387 bitbang_interface = &parport_bitbang;
388
389 wait_states = jtag_get_speed();
390
391 return ERROR_OK;
392 }
393
394 static int parport_quit(void)
395 {
396 parport_led(0);
397
398 if (parport_exit)
399 {
400 dataport_value = cable->PORT_EXIT;
401 parport_write_data();
402 }
403
404 if (parport_cable)
405 {
406 free(parport_cable);
407 parport_cable = NULL;
408 }
409
410 return ERROR_OK;
411 }
412
413 COMMAND_HANDLER(parport_handle_parport_port_command)
414 {
415 if (argc == 1)
416 {
417 /* only if the port wasn't overwritten by cmdline */
418 if (parport_port == 0)
419 {
420 COMMAND_PARSE_NUMBER(u16, args[0], parport_port);
421 }
422 else
423 {
424 LOG_ERROR("The parport port was already configured!");
425 return ERROR_FAIL;
426 }
427 }
428
429 command_print(cmd_ctx, "parport port = %u", parport_port);
430
431 return ERROR_OK;
432 }
433
434 COMMAND_HANDLER(parport_handle_parport_cable_command)
435 {
436 if (argc == 0)
437 return ERROR_OK;
438
439 /* only if the cable name wasn't overwritten by cmdline */
440 if (parport_cable == 0)
441 {
442 parport_cable = malloc(strlen(args[0]) + sizeof(char));
443 strcpy(parport_cable, args[0]);
444 }
445
446 return ERROR_OK;
447 }
448
449 COMMAND_HANDLER(parport_handle_write_on_exit_command)
450 {
451 if (argc != 1)
452 {
453 command_print(cmd_ctx, "usage: parport_write_on_exit <on | off>");
454 return ERROR_OK;
455 }
456
457 if (strcmp(args[0], "on") == 0)
458 parport_exit = 1;
459 else if (strcmp(args[0], "off") == 0)
460 parport_exit = 0;
461
462 return ERROR_OK;
463 }
464
465 COMMAND_HANDLER(parport_handle_parport_toggling_time_command)
466 {
467 if (argc == 1) {
468 uint32_t ns;
469 int retval = parse_u32(args[0], &ns);
470
471 if (ERROR_OK != retval)
472 return retval;
473
474 if (ns == 0) {
475 LOG_ERROR("0 ns is not a valid parport toggling time");
476 return ERROR_FAIL;
477 }
478
479 parport_toggling_time_ns = ns;
480 wait_states = jtag_get_speed();
481 }
482
483 command_print(cmd_ctx, "parport toggling time = %" PRIu32 " ns",
484 parport_toggling_time_ns);
485
486 return ERROR_OK;
487 }
488
489 static int parport_register_commands(struct command_context_s *cmd_ctx)
490 {
491 register_command(cmd_ctx, NULL, "parport_port",
492 parport_handle_parport_port_command, COMMAND_CONFIG,
493 "either the address of the I/O port "
494 "or the number of the '/dev/parport' device");
495
496 register_command(cmd_ctx, NULL, "parport_cable",
497 parport_handle_parport_cable_command, COMMAND_CONFIG,
498 "the layout of the parallel port cable "
499 "used to connect to the target");
500
501 register_command(cmd_ctx, NULL, "parport_write_on_exit",
502 parport_handle_write_on_exit_command, COMMAND_CONFIG,
503 "configure the parallel driver to write "
504 "a known value to the parallel interface");
505
506 register_command(cmd_ctx, NULL, "parport_toggling_time",
507 parport_handle_parport_toggling_time_command, COMMAND_ANY,
508 "time <ns> it takes for the hardware to toggle TCK");
509
510 return ERROR_OK;
511 }
512
513 struct jtag_interface parport_interface = {
514 .name = "parport",
515 .register_commands = parport_register_commands,
516 .init = parport_init,
517 .quit = parport_quit,
518 .khz = parport_khz,
519 .speed_div = parport_speed_div,
520 .speed = parport_speed,
521 .execute_queue = bitbang_execute_queue,
522 };

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)