- added patch for new flash functionality like:
[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 unsigned long 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 .support_pathmove = 1,
163
164 .speed = parport_speed,
165 .register_commands = parport_register_commands,
166 .init = parport_init,
167 .quit = parport_quit,
168 };
169
170 bitbang_interface_t parport_bitbang =
171 {
172 .read = parport_read,
173 .write = parport_write,
174 .reset = parport_reset,
175 .blink = parport_led
176 };
177
178 int parport_read(void)
179 {
180 int data = 0;
181
182 #if PARPORT_USE_PPDEV == 1
183 ioctl(device_handle, PPRSTATUS, & data);
184 #else
185 data = inb(statusport);
186 #endif
187
188 if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
189 return 1;
190 else
191 return 0;
192 }
193
194 static inline void parport_write_data(void)
195 {
196 u8 output;
197 output = dataport_value ^ cable->OUTPUT_INVERT;
198
199 #if PARPORT_USE_PPDEV == 1
200 ioctl(device_handle, PPWDATA, &output);
201 #else
202 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
203 outb(dataport, output);
204 #else
205 outb(output, dataport);
206 #endif
207 #endif
208 }
209
210 void parport_write(int tck, int tms, int tdi)
211 {
212 int i = jtag_speed + 1;
213
214 if (tck)
215 dataport_value |= cable->TCK_MASK;
216 else
217 dataport_value &= ~cable->TCK_MASK;
218
219 if (tms)
220 dataport_value |= cable->TMS_MASK;
221 else
222 dataport_value &= ~cable->TMS_MASK;
223
224 if (tdi)
225 dataport_value |= cable->TDI_MASK;
226 else
227 dataport_value &= ~cable->TDI_MASK;
228
229 while (i-- > 0)
230 parport_write_data();
231 }
232
233 /* (1) assert or (0) deassert reset lines */
234 void parport_reset(int trst, int srst)
235 {
236 DEBUG("trst: %i, srst: %i", trst, srst);
237
238 if (trst == 0)
239 dataport_value |= cable->TRST_MASK;
240 else if (trst == 1)
241 dataport_value &= ~cable->TRST_MASK;
242
243 if (srst == 0)
244 dataport_value |= cable->SRST_MASK;
245 else if (srst == 1)
246 dataport_value &= ~cable->SRST_MASK;
247
248 parport_write_data();
249 }
250
251 /* turn LED on parport adapter on (1) or off (0) */
252 void parport_led(int on)
253 {
254 if (on)
255 dataport_value |= cable->LED_MASK;
256 else
257 dataport_value &= ~cable->LED_MASK;
258
259 parport_write_data();
260 }
261
262 int parport_speed(int speed)
263 {
264 jtag_speed = speed;
265
266 return ERROR_OK;
267 }
268
269 int parport_register_commands(struct command_context_s *cmd_ctx)
270 {
271 register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
272 COMMAND_CONFIG, NULL);
273 register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
274 COMMAND_CONFIG, NULL);
275 register_command(cmd_ctx, NULL, "parport_write_on_exit", parport_handle_write_on_exit_command,
276 COMMAND_CONFIG, NULL);
277
278 return ERROR_OK;
279 }
280
281 #if PARPORT_USE_GIVEIO == 1
282 int parport_get_giveio_access()
283 {
284 HANDLE h;
285 OSVERSIONINFO version;
286
287 version.dwOSVersionInfoSize = sizeof version;
288 if (!GetVersionEx( &version )) {
289 errno = EINVAL;
290 return -1;
291 }
292 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
293 return 0;
294
295 h = CreateFile( "\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
296 if (h == INVALID_HANDLE_VALUE) {
297 errno = ENODEV;
298 return -1;
299 }
300
301 CloseHandle( h );
302
303 return 0;
304 }
305 #endif
306
307 int parport_init(void)
308 {
309 cable_t *cur_cable;
310 #if PARPORT_USE_PPDEV == 1
311 char buffer[256];
312 int i = 0;
313 #endif
314
315 cur_cable = cables;
316
317 if ((parport_cable == NULL) || (parport_cable[0] == 0))
318 {
319 parport_cable = "wiggler";
320 WARNING("No parport cable specified, using default 'wiggler'");
321 }
322
323 while (cur_cable->name)
324 {
325 if (strcmp(cur_cable->name, parport_cable) == 0)
326 {
327 cable = cur_cable;
328 break;
329 }
330 cur_cable++;
331 }
332
333 if (!cable)
334 {
335 ERROR("No matching cable found for %s", parport_cable);
336 return ERROR_JTAG_INIT_FAILED;
337 }
338
339 dataport_value = cable->PORT_INIT;
340
341 #if PARPORT_USE_PPDEV == 1
342 if (device_handle > 0)
343 {
344 ERROR("device is already opened");
345 return ERROR_JTAG_INIT_FAILED;
346 }
347
348 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
349 DEBUG("opening /dev/ppi%d...", parport_port);
350
351 snprintf(buffer, 256, "/dev/ppi%d", parport_port);
352 device_handle = open(buffer, O_WRONLY);
353 #else /* not __FreeBSD__, __FreeBSD_kernel__ */
354 DEBUG("opening /dev/parport%d...", parport_port);
355
356 snprintf(buffer, 256, "/dev/parport%d", parport_port);
357 device_handle = open(buffer, O_WRONLY);
358 #endif /* __FreeBSD__, __FreeBSD_kernel__ */
359
360 if (device_handle < 0)
361 {
362 ERROR("cannot open device. check it exists and that user read and write rights are set");
363 return ERROR_JTAG_INIT_FAILED;
364 }
365
366 DEBUG("...open");
367
368 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
369 i=ioctl(device_handle, PPCLAIM);
370 if (i<0)
371 {
372 ERROR("cannot claim device");
373 return ERROR_JTAG_INIT_FAILED;
374 }
375
376 i = PARPORT_MODE_COMPAT;
377 i= ioctl(device_handle, PPSETMODE, & i);
378 if (i<0)
379 {
380 ERROR(" cannot set compatible mode to device");
381 return ERROR_JTAG_INIT_FAILED;
382 }
383
384 i = IEEE1284_MODE_COMPAT;
385 i = ioctl(device_handle, PPNEGOT, & i);
386 if (i<0)
387 {
388 ERROR("cannot set compatible 1284 mode to device");
389 return ERROR_JTAG_INIT_FAILED;
390 }
391 #endif /* not __FreeBSD__, __FreeBSD_kernel__ */
392
393 #else /* not PARPORT_USE_PPDEV */
394 if (parport_port == 0)
395 {
396 parport_port = 0x378;
397 WARNING("No parport port specified, using default '0x378' (LPT1)");
398 }
399
400 dataport = parport_port;
401 statusport = parport_port + 1;
402
403 DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
404 #if PARPORT_USE_GIVEIO == 1
405 if (parport_get_giveio_access() != 0)
406 #else /* PARPORT_USE_GIVEIO */
407 if (ioperm(dataport, 3, 1) != 0)
408 #endif /* PARPORT_USE_GIVEIO */
409 {
410 ERROR("missing privileges for direct i/o");
411 return ERROR_JTAG_INIT_FAILED;
412 }
413 DEBUG("...privileges granted");
414
415 /* make sure parallel port is in right mode (clear tristate and interrupt */
416 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
417 outb(parport_port + 2, 0x0);
418 #else
419 outb(0x0, parport_port + 2);
420 #endif
421
422 #endif /* PARPORT_USE_PPDEV */
423
424 parport_reset(0, 0);
425 parport_write(0, 0, 0);
426 parport_led(1);
427
428 bitbang_interface = &parport_bitbang;
429
430 return ERROR_OK;
431 }
432
433 int parport_quit(void)
434 {
435 parport_led(0);
436
437 if (parport_exit)
438 {
439 dataport_value = cable->PORT_EXIT;
440 parport_write_data();
441 }
442
443 if (parport_cable)
444 {
445 free(parport_cable);
446 parport_cable = NULL;
447 }
448
449 return ERROR_OK;
450 }
451
452 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
453 {
454 if (argc == 0)
455 return ERROR_OK;
456
457 /* only if the port wasn't overwritten by cmdline */
458 if (parport_port == 0)
459 parport_port = strtoul(args[0], NULL, 0);
460
461 return ERROR_OK;
462 }
463
464 int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
465 {
466 if (argc == 0)
467 return ERROR_OK;
468
469 /* only if the cable name wasn't overwritten by cmdline */
470 if (parport_cable == 0)
471 {
472 parport_cable = malloc(strlen(args[0]) + sizeof(char));
473 strcpy(parport_cable, args[0]);
474 }
475
476 return ERROR_OK;
477 }
478
479 int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
480 {
481 if (argc != 1)
482 {
483 command_print(cmd_ctx, "usage: parport_write_on_exit <on|off>");
484 return ERROR_OK;
485 }
486
487 if (strcmp(args[0], "on") == 0)
488 parport_exit = 1;
489 else if (strcmp(args[0], "off") == 0)
490 parport_exit = 0;
491
492 return ERROR_OK;
493 }

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)