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

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)