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

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)