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

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)