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

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)