Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> one more parport device
[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 #endif
74 #endif
75
76 #include "log.h"
77
78 /* parallel port cable description
79 */
80 typedef struct cable_s
81 {
82 char* name;
83 u8 TDO_MASK; /* status port bit containing current TDO value */
84 u8 TRST_MASK; /* data port bit for TRST */
85 u8 TMS_MASK; /* data port bit for TMS */
86 u8 TCK_MASK; /* data port bit for TCK */
87 u8 TDI_MASK; /* data port bit for TDI */
88 u8 SRST_MASK; /* data port bit for SRST */
89 u8 OUTPUT_INVERT; /* data port bits that should be inverted */
90 u8 INPUT_INVERT; /* status port that should be inverted */
91 u8 PORT_INIT; /* initialize data port with this value */
92 u8 PORT_EXIT; /* de-initialize data port with this value */
93 u8 LED_MASK; /* data port bit for LED */
94 } cable_t;
95
96 cable_t cables[] =
97 {
98 /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
99 { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
100 { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
101 { "wiggler_ntrst_inverted",
102 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
103 { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
104 { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 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 LOG_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 return ERROR_OK;
263 }
264
265 int parport_register_commands(struct command_context_s *cmd_ctx)
266 {
267 register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
268 COMMAND_CONFIG, NULL);
269 register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
270 COMMAND_CONFIG, NULL);
271 register_command(cmd_ctx, NULL, "parport_write_on_exit", parport_handle_write_on_exit_command,
272 COMMAND_CONFIG, NULL);
273
274 return ERROR_OK;
275 }
276
277 #if PARPORT_USE_GIVEIO == 1
278 int parport_get_giveio_access(void)
279 {
280 HANDLE h;
281 OSVERSIONINFO version;
282
283 version.dwOSVersionInfoSize = sizeof version;
284 if (!GetVersionEx( &version )) {
285 errno = EINVAL;
286 return -1;
287 }
288 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
289 return 0;
290
291 h = CreateFile( "\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
292 if (h == INVALID_HANDLE_VALUE) {
293 errno = ENODEV;
294 return -1;
295 }
296
297 CloseHandle( h );
298
299 return 0;
300 }
301 #endif
302
303 int parport_init(void)
304 {
305 cable_t *cur_cable;
306 #if PARPORT_USE_PPDEV == 1
307 char buffer[256];
308 int i = 0;
309 #endif
310
311 cur_cable = cables;
312
313 if ((parport_cable == NULL) || (parport_cable[0] == 0))
314 {
315 parport_cable = "wiggler";
316 LOG_WARNING("No parport cable specified, using default 'wiggler'");
317 }
318
319 while (cur_cable->name)
320 {
321 if (strcmp(cur_cable->name, parport_cable) == 0)
322 {
323 cable = cur_cable;
324 break;
325 }
326 cur_cable++;
327 }
328
329 if (!cable)
330 {
331 LOG_ERROR("No matching cable found for %s", parport_cable);
332 return ERROR_JTAG_INIT_FAILED;
333 }
334
335 dataport_value = cable->PORT_INIT;
336
337 #if PARPORT_USE_PPDEV == 1
338 if (device_handle > 0)
339 {
340 LOG_ERROR("device is already opened");
341 return ERROR_JTAG_INIT_FAILED;
342 }
343
344 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
345 LOG_DEBUG("opening /dev/ppi%d...", parport_port);
346
347 snprintf(buffer, 256, "/dev/ppi%d", parport_port);
348 device_handle = open(buffer, O_WRONLY);
349 #else /* not __FreeBSD__, __FreeBSD_kernel__ */
350 LOG_DEBUG("opening /dev/parport%d...", parport_port);
351
352 snprintf(buffer, 256, "/dev/parport%d", parport_port);
353 device_handle = open(buffer, O_WRONLY);
354 #endif /* __FreeBSD__, __FreeBSD_kernel__ */
355
356 if (device_handle < 0)
357 {
358 LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
359 return ERROR_JTAG_INIT_FAILED;
360 }
361
362 LOG_DEBUG("...open");
363
364 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
365 i=ioctl(device_handle, PPCLAIM);
366 if (i<0)
367 {
368 LOG_ERROR("cannot claim device");
369 return ERROR_JTAG_INIT_FAILED;
370 }
371
372 i = PARPORT_MODE_COMPAT;
373 i= ioctl(device_handle, PPSETMODE, & i);
374 if (i<0)
375 {
376 LOG_ERROR(" cannot set compatible mode to device");
377 return ERROR_JTAG_INIT_FAILED;
378 }
379
380 i = IEEE1284_MODE_COMPAT;
381 i = ioctl(device_handle, PPNEGOT, & i);
382 if (i<0)
383 {
384 LOG_ERROR("cannot set compatible 1284 mode to device");
385 return ERROR_JTAG_INIT_FAILED;
386 }
387 #endif /* not __FreeBSD__, __FreeBSD_kernel__ */
388
389 #else /* not PARPORT_USE_PPDEV */
390 if (parport_port == 0)
391 {
392 parport_port = 0x378;
393 LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
394 }
395
396 dataport = parport_port;
397 statusport = parport_port + 1;
398
399 LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
400 #if PARPORT_USE_GIVEIO == 1
401 if (parport_get_giveio_access() != 0)
402 #else /* PARPORT_USE_GIVEIO */
403 if (ioperm(dataport, 3, 1) != 0)
404 #endif /* PARPORT_USE_GIVEIO */
405 {
406 LOG_ERROR("missing privileges for direct i/o");
407 return ERROR_JTAG_INIT_FAILED;
408 }
409 LOG_DEBUG("...privileges granted");
410
411 /* make sure parallel port is in right mode (clear tristate and interrupt */
412 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
413 outb(parport_port + 2, 0x0);
414 #else
415 outb(0x0, parport_port + 2);
416 #endif
417
418 #endif /* PARPORT_USE_PPDEV */
419
420 parport_reset(0, 0);
421 parport_write(0, 0, 0);
422 parport_led(1);
423
424 bitbang_interface = &parport_bitbang;
425
426 return ERROR_OK;
427 }
428
429 int parport_quit(void)
430 {
431 parport_led(0);
432
433 if (parport_exit)
434 {
435 dataport_value = cable->PORT_EXIT;
436 parport_write_data();
437 }
438
439 if (parport_cable)
440 {
441 free(parport_cable);
442 parport_cable = NULL;
443 }
444
445 return ERROR_OK;
446 }
447
448 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
449 {
450 if (argc == 0)
451 return ERROR_OK;
452
453 /* only if the port wasn't overwritten by cmdline */
454 if (parport_port == 0)
455 parport_port = strtoul(args[0], NULL, 0);
456
457 return ERROR_OK;
458 }
459
460 int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
461 {
462 if (argc == 0)
463 return ERROR_OK;
464
465 /* only if the cable name wasn't overwritten by cmdline */
466 if (parport_cable == 0)
467 {
468 parport_cable = malloc(strlen(args[0]) + sizeof(char));
469 strcpy(parport_cable, args[0]);
470 }
471
472 return ERROR_OK;
473 }
474
475 int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
476 {
477 if (argc != 1)
478 {
479 command_print(cmd_ctx, "usage: parport_write_on_exit <on|off>");
480 return ERROR_OK;
481 }
482
483 if (strcmp(args[0], "on") == 0)
484 parport_exit = 1;
485 else if (strcmp(args[0], "off") == 0)
486 parport_exit = 0;
487
488 return ERROR_OK;
489 }

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)