b666eb123aa80674bc033dff1577194c32422aa9
[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;
124 unsigned long parport_port;
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
154 jtag_interface_t parport_interface =
155 {
156 .name = "parport",
157
158 .execute_queue = bitbang_execute_queue,
159
160 .support_pathmove = 1,
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 u8 output;
253 if (on)
254 dataport_value |= cable->LED_MASK;
255 else
256 dataport_value &= ~cable->LED_MASK;
257
258 parport_write_data();
259 }
260
261 int parport_speed(int speed)
262 {
263 jtag_speed = speed;
264
265 return ERROR_OK;
266 }
267
268 int parport_register_commands(struct command_context_s *cmd_ctx)
269 {
270 register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
271 COMMAND_CONFIG, NULL);
272 register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_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 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 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 ERROR("device is already opened");
342 return ERROR_JTAG_INIT_FAILED;
343 }
344
345 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
346 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 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 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 DEBUG("...open");
364
365 #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
366 i=ioctl(device_handle, PPCLAIM);
367 if (i<0)
368 {
369 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 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 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 WARNING("No parport port specified, using default '0x378' (LPT1)");
395 }
396
397 dataport = parport_port;
398 statusport = parport_port + 1;
399
400 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 ERROR("missing privileges for direct i/o");
408 return ERROR_JTAG_INIT_FAILED;
409 }
410 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 u8 output;
433 parport_led(0);
434
435 dataport_value = cable->PORT_EXIT;
436 parport_write_data();
437 return ERROR_OK;
438 }
439
440 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
441 {
442 if (argc == 0)
443 return ERROR_OK;
444
445 /* only if the port wasn't overwritten by cmdline */
446 if (parport_port == 0)
447 parport_port = strtoul(args[0], NULL, 0);
448
449 return ERROR_OK;
450 }
451
452 int parport_handle_parport_cable_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 cable name wasn't overwritten by cmdline */
458 if (parport_cable == 0)
459 {
460 parport_cable = malloc(strlen(args[0]) + sizeof(char));
461 strcpy(parport_cable, args[0]);
462 }
463
464 return ERROR_OK;
465 }

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)