4b0ffd73853a6c7e3a817dade2cbea026d4c6692
[openocd.git] / src / jtag / gw16012.c
1 /***************************************************************************
2 * Copyright (C) 2006 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 "interface.h"
25 #include "commands.h"
26
27
28 #if 1
29 #define _DEBUG_GW16012_IO_
30 #endif
31
32 /* system includes */
33 /* -ino: 060521-1036 */
34 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
35
36 #include <machine/sysarch.h>
37 #include <machine/cpufunc.h>
38 #define ioperm(startport,length,enable)\
39 i386_set_ioperm((startport), (length), (enable))
40
41 #else
42
43 #endif /* __FreeBSD__, __FreeBSD_kernel__ */
44
45
46 #if PARPORT_USE_PPDEV == 1
47 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
48 #include <dev/ppbus/ppi.h>
49 #include <dev/ppbus/ppbconf.h>
50 #define PPRSTATUS PPIGSTATUS
51 #define PPWDATA PPISDATA
52 #else
53 #include <linux/parport.h>
54 #include <linux/ppdev.h>
55 #endif
56 #include <fcntl.h>
57 #include <sys/ioctl.h>
58 #else /* not PARPORT_USE_PPDEV */
59 #ifndef _WIN32
60 #include <sys/io.h>
61 #endif
62 #endif
63
64 #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1
65 #include <windows.h>
66 #endif
67
68
69 /* configuration */
70 uint16_t gw16012_port;
71
72 /* interface variables
73 */
74 static uint8_t gw16012_msb = 0x0;
75 static uint8_t gw16012_control_value = 0x0;
76
77 #if PARPORT_USE_PPDEV == 1
78 static int device_handle;
79 #endif
80
81 static int gw16012_execute_queue(void);
82 static int gw16012_register_commands(struct command_context_s *cmd_ctx);
83 static int gw16012_speed(int speed);
84 static int gw16012_init(void);
85 static int gw16012_quit(void);
86
87 static int gw16012_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
88
89 jtag_interface_t gw16012_interface =
90 {
91 .name = "gw16012",
92
93 .execute_queue = gw16012_execute_queue,
94
95 .speed = gw16012_speed,
96 .register_commands = gw16012_register_commands,
97 .init = gw16012_init,
98 .quit = gw16012_quit,
99 };
100
101 static int gw16012_register_commands(struct command_context_s *cmd_ctx)
102 {
103 register_command(cmd_ctx, NULL, "parport_port", gw16012_handle_parport_port_command,
104 COMMAND_CONFIG, NULL);
105
106 return ERROR_OK;
107 }
108
109 static void gw16012_data(uint8_t value)
110 {
111 value = (value & 0x7f) | gw16012_msb;
112 gw16012_msb ^= 0x80; /* toggle MSB */
113
114 #ifdef _DEBUG_GW16012_IO_
115 LOG_DEBUG("%2.2x", value);
116 #endif
117
118 #if PARPORT_USE_PPDEV == 1
119 ioctl(device_handle, PPWDATA, &value);
120 #else
121 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
122 outb(gw16012_port, value);
123 #else
124 outb(value, gw16012_port);
125 #endif
126 #endif
127 }
128
129 static void gw16012_control(uint8_t value)
130 {
131 if (value != gw16012_control_value)
132 {
133 gw16012_control_value = value;
134
135 #ifdef _DEBUG_GW16012_IO_
136 LOG_DEBUG("%2.2x", gw16012_control_value);
137 #endif
138
139 #if PARPORT_USE_PPDEV == 1
140 ioctl(device_handle, PPWCONTROL, &gw16012_control_value);
141 #else
142 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
143 outb(gw16012_port + 2, gw16012_control_value);
144 #else
145 outb(gw16012_control_value, gw16012_port + 2);
146 #endif
147 #endif
148 }
149 }
150
151 static void gw16012_input(uint8_t *value)
152 {
153 #if PARPORT_USE_PPDEV == 1
154 ioctl(device_handle, PPRSTATUS, value);
155 #else
156 *value = inb(gw16012_port + 1);
157 #endif
158
159 #ifdef _DEBUG_GW16012_IO_
160 LOG_DEBUG("%2.2x", *value);
161 #endif
162 }
163
164 /* (1) assert or (0) deassert reset lines */
165 static void gw16012_reset(int trst, int srst)
166 {
167 LOG_DEBUG("trst: %i, srst: %i", trst, srst);
168
169 if (trst == 0)
170 gw16012_control(0x0d);
171 else if (trst == 1)
172 gw16012_control(0x0c);
173
174 if (srst == 0)
175 gw16012_control(0x0a);
176 else if (srst == 1)
177 gw16012_control(0x0b);
178 }
179
180 static int gw16012_speed(int speed)
181 {
182
183 return ERROR_OK;
184 }
185
186 static void gw16012_end_state(tap_state_t state)
187 {
188 if (tap_is_state_stable(state))
189 tap_set_end_state(state);
190 else
191 {
192 LOG_ERROR("BUG: %i is not a valid end state", state);
193 exit(-1);
194 }
195 }
196
197 static void gw16012_state_move(void)
198 {
199 int i = 0, tms = 0;
200 uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
201 int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
202
203 gw16012_control(0x0); /* single-bit mode */
204
205 for (i = 0; i < tms_count; i++)
206 {
207 tms = (tms_scan >> i) & 1;
208 gw16012_data(tms << 1); /* output next TMS bit */
209 }
210
211 tap_set_state(tap_get_end_state());
212 }
213
214 static void gw16012_path_move(pathmove_command_t *cmd)
215 {
216 int num_states = cmd->num_states;
217 int state_count;
218
219 state_count = 0;
220 while (num_states)
221 {
222 gw16012_control(0x0); /* single-bit mode */
223 if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count])
224 {
225 gw16012_data(0x0); /* TCK cycle with TMS low */
226 }
227 else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count])
228 {
229 gw16012_data(0x2); /* TCK cycle with TMS high */
230 }
231 else
232 {
233 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count]));
234 exit(-1);
235 }
236
237 tap_set_state(cmd->path[state_count]);
238 state_count++;
239 num_states--;
240 }
241
242 tap_set_end_state(tap_get_state());
243 }
244
245 static void gw16012_runtest(int num_cycles)
246 {
247 tap_state_t saved_end_state = tap_get_end_state();
248 int i;
249
250 /* only do a state_move when we're not already in IDLE */
251 if (tap_get_state() != TAP_IDLE)
252 {
253 gw16012_end_state(TAP_IDLE);
254 gw16012_state_move();
255 }
256
257 for (i = 0; i < num_cycles; i++)
258 {
259 gw16012_control(0x0); /* single-bit mode */
260 gw16012_data(0x0); /* TMS cycle with TMS low */
261 }
262
263 gw16012_end_state(saved_end_state);
264 if (tap_get_state() != tap_get_end_state())
265 gw16012_state_move();
266 }
267
268 static void gw16012_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
269 {
270 int bits_left = scan_size;
271 int bit_count = 0;
272 tap_state_t saved_end_state = tap_get_end_state();
273 uint8_t scan_out, scan_in;
274
275 /* only if we're not already in the correct Shift state */
276 if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT))))
277 {
278 if (ir_scan)
279 gw16012_end_state(TAP_IRSHIFT);
280 else
281 gw16012_end_state(TAP_DRSHIFT);
282
283 gw16012_state_move();
284 gw16012_end_state(saved_end_state);
285 }
286
287 while (type == SCAN_OUT && ((bits_left - 1) > 7))
288 {
289 gw16012_control(0x2); /* seven-bit mode */
290 scan_out = buf_get_u32(buffer, bit_count, 7);
291 gw16012_data(scan_out);
292 bit_count += 7;
293 bits_left -= 7;
294 }
295
296 gw16012_control(0x0); /* single-bit mode */
297 while (bits_left-- > 0)
298 {
299 uint8_t tms = 0;
300
301 scan_out = buf_get_u32(buffer, bit_count, 1);
302
303 if (bits_left == 0) /* last bit */
304 {
305 if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT))
306 || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT)))
307 {
308 tms = 0;
309 }
310 else
311 {
312 tms = 2;
313 }
314 }
315
316 gw16012_data(scan_out | tms);
317
318 if (type != SCAN_OUT)
319 {
320 gw16012_input(&scan_in);
321 buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3));
322 }
323
324 bit_count++;
325 }
326
327 if (!((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) ||
328 (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))))
329 {
330 gw16012_data(0x0);
331 if (ir_scan)
332 tap_set_state(TAP_IRPAUSE);
333 else
334 tap_set_state(TAP_DRPAUSE);
335
336 if (tap_get_state() != tap_get_end_state())
337 gw16012_state_move();
338 }
339 }
340
341 static int gw16012_execute_queue(void)
342 {
343 jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
344 int scan_size;
345 enum scan_type type;
346 uint8_t *buffer;
347 int retval;
348
349 /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
350 * that wasn't handled by a caller-provided error handler
351 */
352 retval = ERROR_OK;
353
354 while (cmd)
355 {
356 switch (cmd->type)
357 {
358 case JTAG_RESET:
359 #ifdef _DEBUG_JTAG_IO_
360 LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
361 #endif
362 if (cmd->cmd.reset->trst == 1)
363 {
364 tap_set_state(TAP_RESET);
365 }
366 gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
367 break;
368 case JTAG_RUNTEST:
369 #ifdef _DEBUG_JTAG_IO_
370 LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
371 #endif
372 gw16012_end_state(cmd->cmd.runtest->end_state);
373 gw16012_runtest(cmd->cmd.runtest->num_cycles);
374 break;
375 case JTAG_STATEMOVE:
376 #ifdef _DEBUG_JTAG_IO_
377 LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
378 #endif
379 gw16012_end_state(cmd->cmd.statemove->end_state);
380 gw16012_state_move();
381 break;
382 case JTAG_PATHMOVE:
383 #ifdef _DEBUG_JTAG_IO_
384 LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
385 #endif
386 gw16012_path_move(cmd->cmd.pathmove);
387 break;
388 case JTAG_SCAN:
389 gw16012_end_state(cmd->cmd.scan->end_state);
390 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
391 type = jtag_scan_type(cmd->cmd.scan);
392 #ifdef _DEBUG_JTAG_IO_
393 LOG_DEBUG("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr",
394 type, scan_size, cmd->cmd.scan->end_state);
395 #endif
396 gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
397 if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
398 retval = ERROR_JTAG_QUEUE_FAILED;
399 if (buffer)
400 free(buffer);
401 break;
402 case JTAG_SLEEP:
403 #ifdef _DEBUG_JTAG_IO_
404 LOG_DEBUG("sleep %i", cmd->cmd.sleep->us);
405 #endif
406 jtag_sleep(cmd->cmd.sleep->us);
407 break;
408 default:
409 LOG_ERROR("BUG: unknown JTAG command type encountered");
410 exit(-1);
411 }
412 cmd = cmd->next;
413 }
414
415 return retval;
416 }
417
418 #if PARPORT_USE_GIVEIO == 1
419 static int gw16012_get_giveio_access(void)
420 {
421 HANDLE h;
422 OSVERSIONINFO version;
423
424 version.dwOSVersionInfoSize = sizeof version;
425 if (!GetVersionEx(&version)) {
426 errno = EINVAL;
427 return -1;
428 }
429 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
430 return 0;
431
432 h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
433 if (h == INVALID_HANDLE_VALUE) {
434 errno = ENODEV;
435 return -1;
436 }
437
438 CloseHandle(h);
439
440 return 0;
441 }
442 #endif
443
444 #if PARPORT_USE_PPDEV == 1
445
446 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
447
448 #define GW16012_PPDEV_NAME "ppi"
449
450 static int gw16012_init_ioctls(void)
451 {
452 int temp = 0;
453 temp = ioctl(device_handle, PPCLAIM);
454 if (temp < 0)
455 {
456 LOG_ERROR("cannot claim device");
457 return ERROR_JTAG_INIT_FAILED;
458 }
459
460 temp = PARPORT_MODE_COMPAT;
461 temp = ioctl(device_handle, PPSETMODE, &temp);
462 if (temp < 0)
463 {
464 LOG_ERROR(" cannot set compatible mode to device");
465 return ERROR_JTAG_INIT_FAILED;
466 }
467
468 temp = IEEE1284_MODE_COMPAT;
469 temp = ioctl(device_handle, PPNEGOT, &temp);
470 if (temp < 0)
471 {
472 LOG_ERROR("cannot set compatible 1284 mode to device");
473 return ERROR_JTAG_INIT_FAILED;
474 }
475 return ERROR_OK;
476 }
477 #else
478
479 #define GW16012_PPDEV_NAME "parport"
480
481 static int gw16012_init_ioctls(void)
482 {
483 return ERROR_OK;
484 }
485
486 #endif // defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
487
488 static int gw16012_init_device(void)
489 {
490 const char *device_name = GW16012_PPDEV_NAME;
491 char buffer[256];
492
493 if (device_handle > 0)
494 {
495 LOG_ERROR("device is already opened");
496 return ERROR_JTAG_INIT_FAILED;
497 }
498
499 snprintf(buffer, 256, "/dev/%s%d", device_name, gw16012_port);
500 LOG_DEBUG("opening %s...", buffer);
501
502 device_handle = open(buffer, O_WRONLY);
503 if (device_handle < 0)
504 {
505 LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
506 return ERROR_JTAG_INIT_FAILED;
507 }
508
509 LOG_DEBUG("...open");
510
511 if (gw16012_init_ioctls() != ERROR_OK)
512 return ERROR_JTAG_INIT_FAILED;
513
514 return ERROR_OK;
515 }
516
517 #else // PARPORT_USE_PPDEV
518
519 static int gw16012_init_device(void)
520 {
521 if (gw16012_port == 0)
522 {
523 gw16012_port = 0x378;
524 LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)");
525 }
526
527 LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port));
528 #if PARPORT_USE_GIVEIO == 1
529 if (gw16012_get_giveio_access() != 0)
530 #else /* PARPORT_USE_GIVEIO */
531 if (ioperm(gw16012_port, 3, 1) != 0)
532 #endif /* PARPORT_USE_GIVEIO */
533 {
534 LOG_ERROR("missing privileges for direct i/o");
535 return ERROR_JTAG_INIT_FAILED;
536 }
537 LOG_DEBUG("...privileges granted");
538
539 /* make sure parallel port is in right mode (clear tristate and interrupt */
540 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
541 outb(gw16012_port + 2, 0x0);
542 #else
543 outb(0x0, gw16012_port + 2);
544 #endif
545 return ERROR_OK;
546 }
547
548 #endif // PARPORT_USE_PPDEV
549
550 static int gw16012_init(void)
551 {
552 uint8_t status_port;
553
554 if (gw16012_init_device() != ERROR_OK)
555 return ERROR_JTAG_INIT_FAILED;
556
557 gw16012_input(&status_port);
558 gw16012_msb = (status_port & 0x80) ^ 0x80;
559
560 gw16012_speed(jtag_get_speed());
561 gw16012_reset(0, 0);
562
563 return ERROR_OK;
564 }
565
566 static int gw16012_quit(void)
567 {
568
569 return ERROR_OK;
570 }
571
572 static int gw16012_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
573 {
574 if (argc == 1)
575 {
576 /* only if the port wasn't overwritten by cmdline */
577 if (gw16012_port == 0)
578 {
579 COMMAND_PARSE_NUMBER(u16, args[0], gw16012_port);
580 }
581 else
582 {
583 LOG_ERROR("The parport port was already configured!");
584 return ERROR_FAIL;
585 }
586 }
587
588 command_print(cmd_ctx, "parport port = %u", gw16012_port);
589
590 return ERROR_OK;
591 }

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)