source: sandbox/JamPlayerUSB/jbistub.c@ 168

Last change on this file since 168 was 112, checked in by demin, 14 years ago

use usleep for jbi_delay and remove unused includes

File size: 20.8 KB
Line 
1/****************************************************************************/
2/* */
3/* Module: jbistub.c */
4/* */
5/* Copyright (C) Altera Corporation 1997-2001 */
6/* */
7/* Description: Jam STAPL ByteCode Player main source file */
8/* */
9/* Supports Altera ByteBlaster hardware download cable */
10/* on Windows 95 and Windows NT operating systems. */
11/* (A device driver is required for Windows NT.) */
12/* */
13/* Also supports BitBlaster hardware download cable on */
14/* Windows 95, Windows NT, and UNIX platforms. */
15/* */
16/* Revisions: 1.1 fixed control port initialization for ByteBlaster */
17/* 2.0 added support for STAPL bytecode format, added code */
18/* to get printer port address from Windows registry */
19/* 2.1 improved messages, fixed delay-calibration bug in */
20/* 16-bit DOS port, added support for "alternative */
21/* cable X", added option to control whether to reset */
22/* the TAP after execution, moved porting macros into */
23/* jbiport.h */
24/* 2.2 added support for static memory */
25/* fixed /W4 warnings */
26/* */
27/****************************************************************************/
28
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
32#include <malloc.h>
33#include <ctype.h>
34#include <sys/stat.h>
35
36#define POINTER_ALIGNMENT sizeof(BYTE)
37
38#include "jbiexprt.h"
39
40/************************************************************************
41*
42* Global variables
43*/
44
45unsigned char *file_buffer = NULL;
46long file_pointer = 0L;
47long file_length = 0L;
48
49/******************************************************************/
50
51#include <windows.h>
52#include "ftd2xx.h"
53
54BOOL jtag_hardware_initialized = FALSE;
55
56BOOL verbose = FALSE;
57
58static FT_HANDLE ftdih = NULL;
59
60/******************************************************************/
61
62int usb_blaster_buf_write(BYTE *buf, int size, DWORD* bytes_written)
63{
64 FT_STATUS status;
65 DWORD dw_bytes_written;
66 if((size == 1) && (buf[0]&0x01)) printf("(tms tdi) -> (%d %d)\n", (buf[0]&0x02) >> 1, (buf[0]&0x10) >> 4);
67 if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK)
68 {
69 *bytes_written = dw_bytes_written;
70 printf("FT_Write returned: %ld\n", status);
71 return 0;
72 }
73 else
74 {
75 *bytes_written = dw_bytes_written;
76 return 1;
77 }
78}
79
80/******************************************************************/
81
82int usb_blaster_buf_read(BYTE* buf, int size, DWORD* bytes_read)
83{
84 DWORD dw_bytes_read;
85 FT_STATUS status;
86 if ((status = FT_Read(ftdih, buf, size, &dw_bytes_read)) != FT_OK)
87 {
88 *bytes_read = dw_bytes_read;
89 printf("FT_Read returned: %ld", status);
90 return 0;
91 }
92 *bytes_read = dw_bytes_read;
93 return 1;
94}
95
96/******************************************************************/
97
98int usb_blaster_init()
99{
100 BYTE latency_timer;
101
102 FT_STATUS status;
103
104 if ((status = FT_OpenEx("USB-Blaster", FT_OPEN_BY_DESCRIPTION, &ftdih)) != FT_OK)
105 {
106 printf("unable to open ftdi device: %ld\n", status);
107 return 0;
108 }
109
110 if ((status = FT_SetLatencyTimer(ftdih, 2)) != FT_OK)
111 {
112 printf("unable to set latency timer: %ld\n", status);
113 return 0;
114 }
115
116 if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK)
117 {
118 printf("unable to get latency timer: %ld\n", status);
119 return 0;
120 }
121 else
122 {
123 printf("current latency timer: %d\n", latency_timer);
124 }
125
126 if ((status = FT_SetBitMode(ftdih, 0x00, 0)) != FT_OK)
127 {
128 printf("unable to disable bit i/o mode: %ld\n", status);
129 return 0;
130 }
131
132 return 1;
133}
134
135/******************************************************************/
136
137int usb_blaster_quit()
138{
139 FT_STATUS status;
140
141 status = FT_Close(ftdih);
142
143 return 1;
144}
145
146/******************************************************************/
147
148void usb_blaster_wait(int count, int tms)
149{
150 DWORD cnt;
151
152 BYTE buf[64];
153
154 int i, len, extra;
155
156 if (count <= 0) return;
157
158 memset(buf, 0, 64);
159
160 extra = (count & 7);
161
162 buf[0] = 0x0C | (tms ? 0x02 : 0);
163 usb_blaster_buf_write(buf, 1, &cnt);
164
165 while (count > 0)
166 {
167 if (count > 504)
168 {
169 len = 63;
170 count -= 504;
171 }
172 else
173 {
174 len = count >> 3;
175 count = 0;
176 }
177
178 if (len > 0)
179 {
180 buf[0] = len | 0x80;
181 usb_blaster_buf_write(buf, len + 1, &cnt);
182 }
183 }
184 for (i = 0; i < extra; i++)
185 {
186 jbi_jtag_io(tms, 0, 0);
187 }
188}
189
190/******************************************************************/
191
192void usb_blaster_scan(int count, unsigned char *tdi, unsigned char *tdo)
193{
194 DWORD cnt;
195
196 BYTE buf[64];
197
198 unsigned char extra_bits;
199
200 int i, len, pos, extra, tdo_bit, read_tdo;
201
202 read_tdo = (tdo != NULL);
203
204 if (count <= 0) return;
205
206 pos = 0;
207 extra = (count & 7);
208
209 if (extra == 0)
210 {
211 count -= 8;
212 extra = 8;
213 }
214
215 extra_bits = tdi[count >> 3];
216
217 while (count > 0)
218 {
219 if (count > 504)
220 {
221 len = 63;
222 count -= 504;
223 }
224 else
225 {
226 len = count >> 3;
227 count = 0;
228 }
229
230 if (len > 0)
231 {
232 buf[0] = len | 0x80 | (read_tdo ? 0x40 : 0);
233 memcpy(buf + 1, tdi + pos, len);
234 usb_blaster_buf_write(buf, len + 1, &cnt);
235 if (read_tdo)
236 {
237 usb_blaster_buf_read(tdo + pos, len, &cnt);
238 }
239 pos += len;
240 }
241 }
242 for (i = 0; i < extra; i++)
243 {
244 tdo_bit = jbi_jtag_io(
245 (i == extra - 1),
246 extra_bits & (1 << (i & 7)),
247 read_tdo);
248
249 if (read_tdo)
250 {
251 if (tdo_bit)
252 {
253 tdo[pos] |= (1 << (i & 7));
254 }
255 else
256 {
257 tdo[pos] &= ~(unsigned int) (1 << (i & 7));
258 }
259 }
260 }
261}
262
263/************************************************************************
264*
265* Customized interface functions for Jam STAPL ByteCode Player I/O:
266*
267* jbi_jtag_io()
268* jbi_message()
269* jbi_delay()
270*/
271
272int jbi_jtag_io(int tms, int tdi, int read_tdo)
273{
274 BYTE buf[3];
275 DWORD count;
276
277 int data = 0;
278 int tdo = 0;
279
280 if (!jtag_hardware_initialized)
281 {
282 usb_blaster_init();
283 jtag_hardware_initialized = TRUE;
284 }
285
286 data = (tdi ? 0x10 : 0) | (tms ? 0x02 : 0);
287
288 buf[0] = data | 0x0C | (read_tdo ? 0x40 : 0);
289 buf[1] = data | 0x0C | 0x01;
290 buf[2] = data | 0x0C;
291 usb_blaster_buf_write(buf, 3, &count);
292
293 if (read_tdo)
294 {
295 usb_blaster_buf_read(buf, 1, &count);
296 tdo = buf[0]&0x01;
297 }
298
299 return (tdo);
300}
301
302void jbi_message(char *message_text)
303{
304 puts(message_text);
305 fflush(stdout);
306}
307
308void jbi_export_integer(char *key, long value)
309{
310 if (verbose)
311 {
312 printf("Export: key = \"%s\", value = %ld\n", key, value);
313 fflush(stdout);
314 }
315}
316
317#define HEX_LINE_CHARS 72
318#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
319
320char conv_to_hex(unsigned long value)
321{
322 char c;
323
324 if (value > 9)
325 {
326 c = (char) (value + ('A' - 10));
327 }
328 else
329 {
330 c = (char) (value + '0');
331 }
332
333 return (c);
334}
335
336void jbi_export_boolean_array(char *key, unsigned char *data, long count)
337{
338 char string[HEX_LINE_CHARS + 1];
339 long i, offset;
340 unsigned long size, line, lines, linebits, value, j, k;
341
342 if (verbose)
343 {
344 if (count > HEX_LINE_BITS)
345 {
346 printf("Export: key = \"%s\", %ld bits, value = HEX\n", key, count);
347 lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
348
349 for (line = 0; line < lines; ++line)
350 {
351 if (line < (lines - 1))
352 {
353 linebits = HEX_LINE_BITS;
354 size = HEX_LINE_CHARS;
355 offset = count - ((line + 1) * HEX_LINE_BITS);
356 }
357 else
358 {
359 linebits = count - ((lines - 1) * HEX_LINE_BITS);
360 size = (linebits + 3) / 4;
361 offset = 0L;
362 }
363
364 string[size] = '\0';
365 j = size - 1;
366 value = 0;
367
368 for (k = 0; k < linebits; ++k)
369 {
370 i = k + offset;
371 if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
372 if ((i & 3) == 3)
373 {
374 string[j] = conv_to_hex(value);
375 value = 0;
376 --j;
377 }
378 }
379 if ((k & 3) > 0) string[j] = conv_to_hex(value);
380
381 printf("%s\n", string);
382 }
383
384 fflush(stdout);
385 }
386 else
387 {
388 size = (count + 3) / 4;
389 string[size] = '\0';
390 j = size - 1;
391 value = 0;
392
393 for (i = 0; i < count; ++i)
394 {
395 if (data[i >> 3] & (1 << (i & 7))) value |= (1 << (i & 3));
396 if ((i & 3) == 3)
397 {
398 string[j] = conv_to_hex(value);
399 value = 0;
400 --j;
401 }
402 }
403 if ((i & 3) > 0) string[j] = conv_to_hex(value);
404
405 printf("Export: key = \"%s\", %ld bits, value = HEX %s\n",
406 key, count, string);
407 fflush(stdout);
408 }
409 }
410}
411
412void jbi_delay(long microseconds)
413{
414 usleep(microseconds);
415}
416
417void *jbi_malloc(unsigned int size)
418{
419 unsigned int n_bytes_to_allocate =
420 (POINTER_ALIGNMENT * ((size + POINTER_ALIGNMENT - 1) / POINTER_ALIGNMENT));
421
422 unsigned char *ptr = 0;
423
424 ptr = (unsigned char *) malloc(n_bytes_to_allocate);
425
426 return ptr;
427}
428
429void jbi_free(void *ptr)
430{
431 if (ptr != 0)
432 {
433 free(ptr);
434 }
435}
436
437char *error_text[] =
438{
439/* JBIC_SUCCESS 0 */ "success",
440/* JBIC_OUT_OF_MEMORY 1 */ "out of memory",
441/* JBIC_IO_ERROR 2 */ "file access error",
442/* JAMC_SYNTAX_ERROR 3 */ "syntax error",
443/* JBIC_UNEXPECTED_END 4 */ "unexpected end of file",
444/* JBIC_UNDEFINED_SYMBOL 5 */ "undefined symbol",
445/* JAMC_REDEFINED_SYMBOL 6 */ "redefined symbol",
446/* JBIC_INTEGER_OVERFLOW 7 */ "integer overflow",
447/* JBIC_DIVIDE_BY_ZERO 8 */ "divide by zero",
448/* JBIC_CRC_ERROR 9 */ "CRC mismatch",
449/* JBIC_INTERNAL_ERROR 10 */ "internal error",
450/* JBIC_BOUNDS_ERROR 11 */ "bounds error",
451/* JAMC_TYPE_MISMATCH 12 */ "type mismatch",
452/* JAMC_ASSIGN_TO_CONST 13 */ "assignment to constant",
453/* JAMC_NEXT_UNEXPECTED 14 */ "NEXT unexpected",
454/* JAMC_POP_UNEXPECTED 15 */ "POP unexpected",
455/* JAMC_RETURN_UNEXPECTED 16 */ "RETURN unexpected",
456/* JAMC_ILLEGAL_SYMBOL 17 */ "illegal symbol name",
457/* JBIC_VECTOR_MAP_FAILED 18 */ "vector signal name not found",
458/* JBIC_USER_ABORT 19 */ "execution cancelled",
459/* JBIC_STACK_OVERFLOW 20 */ "stack overflow",
460/* JBIC_ILLEGAL_OPCODE 21 */ "illegal instruction code",
461/* JAMC_PHASE_ERROR 22 */ "phase error",
462/* JAMC_SCOPE_ERROR 23 */ "scope error",
463/* JBIC_ACTION_NOT_FOUND 24 */ "action not found",
464};
465
466#define MAX_ERROR_CODE (int)((sizeof(error_text)/sizeof(error_text[0]))+1)
467
468/************************************************************************/
469
470int main(int argc, char **argv)
471{
472 BOOL help = FALSE;
473 BOOL error = FALSE;
474 char *filename = NULL;
475 long offset = 0L;
476 long error_address = 0L;
477 JBI_RETURN_TYPE crc_result = JBIC_SUCCESS;
478 JBI_RETURN_TYPE exec_result = JBIC_SUCCESS;
479 unsigned short expected_crc = 0;
480 unsigned short actual_crc = 0;
481 char key[33] = {0};
482 char value[257] = {0};
483 int exit_status = 0;
484 int arg = 0;
485 int exit_code = 0;
486 int format_version = 0;
487 char *workspace = NULL;
488 char *action = NULL;
489 char *init_list[10];
490 int init_count = 0;
491 FILE *fp = NULL;
492 struct stat sbuf;
493 long workspace_size = 0;
494 char *exit_string = NULL;
495 int reset_jtag = 1;
496 int execute_program = 1;
497 int action_count = 0;
498 int procedure_count = 0;
499 int index = 0;
500 char *action_name = NULL;
501 char *description = NULL;
502 JBI_PROCINFO *procedure_list = NULL;
503 JBI_PROCINFO *procptr = NULL;
504
505 verbose = FALSE;
506
507 init_list[0] = NULL;
508
509 /* print out the version string and copyright message */
510 fprintf(stderr, "Jam STAPL ByteCode Player Version 2.2\nCopyright (C) 1998-2001 Altera Corporation\n\n");
511
512 for (arg = 1; arg < argc; arg++)
513 {
514 if (argv[arg][0] == '-')
515 {
516 switch(toupper(argv[arg][1]))
517 {
518 case 'A': /* set action name */
519 if (action == NULL)
520 {
521 action = &argv[arg][2];
522 }
523 else
524 {
525 error = TRUE;
526 }
527 break;
528
529 case 'D': /* initialization list */
530 if (argv[arg][2] == '"')
531 {
532 init_list[init_count] = &argv[arg][3];
533 }
534 else
535 {
536 init_list[init_count] = &argv[arg][2];
537 }
538 init_list[++init_count] = NULL;
539 break;
540
541 case 'R': /* don't reset the JTAG chain after use */
542 reset_jtag = 0;
543 break;
544
545 case 'M': /* set memory size */
546 if (sscanf(&argv[arg][2], "%ld", &workspace_size) != 1)
547 error = TRUE;
548 if (workspace_size == 0) error = TRUE;
549 break;
550
551 case 'H': /* help */
552 help = TRUE;
553 break;
554
555 case 'V': /* verbose */
556 verbose = TRUE;
557 break;
558
559 case 'I': /* show info only, do not execute */
560 verbose = TRUE;
561 execute_program = 0;
562 break;
563
564 default:
565 error = TRUE;
566 break;
567 }
568 }
569 else
570 {
571 /* it's a filename */
572 if (filename == NULL)
573 {
574 filename = argv[arg];
575 }
576 else
577 {
578 /* error -- we already found a filename */
579 error = TRUE;
580 }
581 }
582
583 if (error)
584 {
585 fprintf(stderr, "Illegal argument: \"%s\"\n", argv[arg]);
586 help = TRUE;
587 error = FALSE;
588 }
589 }
590
591 if (help || (filename == NULL))
592 {
593 fprintf(stderr, "Usage: jbi [options] <filename>\n");
594 fprintf(stderr, "\nAvailable options:\n");
595 fprintf(stderr, " -h : show help message\n");
596 fprintf(stderr, " -v : show verbose messages\n");
597 fprintf(stderr, " -i : show file info only - does not execute any action\n");
598 fprintf(stderr, " -a<action> : specify an action name (Jam STAPL)\n");
599 fprintf(stderr, " -d<var=val> : initialize variable to specified value (Jam 1.1)\n");
600 fprintf(stderr, " -d<proc=1> : enable optional procedure (Jam STAPL)\n");
601 fprintf(stderr, " -d<proc=0> : disable recommended procedure (Jam STAPL)\n");
602 fprintf(stderr, " -r : don't reset JTAG TAP after use\n");
603 exit_status = 1;
604 }
605 else if ((workspace_size > 0) &&
606 ((workspace = (char *) jbi_malloc((size_t) workspace_size)) == NULL))
607 {
608 fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
609 (int) (workspace_size / 1024L));
610 exit_status = 1;
611 }
612 else if (access(filename, 0) != 0)
613 {
614 fprintf(stderr, "Error: can't access file \"%s\"\n", filename);
615 exit_status = 1;
616 }
617 else
618 {
619 /* get length of file */
620 if (stat(filename, &sbuf) == 0) file_length = sbuf.st_size;
621
622 if ((fp = fopen(filename, "rb")) == NULL)
623 {
624 fprintf(stderr, "Error: can't open file \"%s\"\n", filename);
625 exit_status = 1;
626 }
627 else
628 {
629 /*
630 * Read entire file into a buffer
631 */
632 file_buffer = (unsigned char *) jbi_malloc((size_t) file_length);
633
634 if (file_buffer == NULL)
635 {
636 fprintf(stderr, "Error: can't allocate memory (%d Kbytes)\n",
637 (int) (file_length / 1024L));
638 exit_status = 1;
639 }
640 else
641 {
642 if (fread(file_buffer, 1, (size_t) file_length, fp) !=
643 (size_t) file_length)
644 {
645 fprintf(stderr, "Error reading file \"%s\"\n", filename);
646 exit_status = 1;
647 }
648 }
649
650 fclose(fp);
651 }
652
653 if (exit_status == 0)
654 {
655 /*
656 * Check CRC
657 */
658 crc_result = jbi_check_crc(file_buffer, file_length,
659 &expected_crc, &actual_crc);
660
661 if (verbose || (crc_result == JBIC_CRC_ERROR))
662 {
663 switch (crc_result)
664 {
665 case JBIC_SUCCESS:
666 printf("CRC matched: CRC value = %04X\n", actual_crc);
667 break;
668
669 case JBIC_CRC_ERROR:
670 printf("CRC mismatch: expected %04X, actual %04X\n",
671 expected_crc, actual_crc);
672 break;
673
674 case JBIC_UNEXPECTED_END:
675 printf("Expected CRC not found, actual CRC value = %04X\n",
676 actual_crc);
677 break;
678
679 case JBIC_IO_ERROR:
680 printf("Error: File format is not recognized.\n");
681 exit(1);
682 break;
683
684 default:
685 printf("CRC function returned error code %d\n", crc_result);
686 break;
687 }
688 }
689
690 if (verbose)
691 {
692 /*
693 * Display file format version
694 */
695 jbi_get_file_info(file_buffer, file_length,
696 &format_version, &action_count, &procedure_count);
697
698 printf("File format is %s ByteCode format\n",
699 (format_version == 2) ? "Jam STAPL" : "pre-standardized Jam 1.1");
700
701 /*
702 * Dump out NOTE fields
703 */
704 while (jbi_get_note(file_buffer, file_length,
705 &offset, key, value, 256) == 0)
706 {
707 printf("NOTE \"%s\" = \"%s\"\n", key, value);
708 }
709
710 /*
711 * Dump the action table
712 */
713 if ((format_version == 2) && (action_count > 0))
714 {
715 printf("\nActions available in this file:\n");
716
717 for (index = 0; index < action_count; ++index)
718 {
719 jbi_get_action_info(file_buffer, file_length,
720 index, &action_name, &description, &procedure_list);
721
722 if (description == NULL)
723 {
724 printf("%s\n", action_name);
725 }
726 else
727 {
728 printf("%s \"%s\"\n", action_name, description);
729 }
730
731 procptr = procedure_list;
732 while (procptr != NULL)
733 {
734 if (procptr->attributes != 0)
735 {
736 printf(" %s (%s)\n", procptr->name,
737 (procptr->attributes == 1) ?
738 "optional" : "recommended");
739 }
740
741 procedure_list = procptr->next;
742 jbi_free(procptr);
743 procptr = procedure_list;
744 }
745 }
746
747 /* add a blank line before execution messages */
748 if (execute_program) printf("\n");
749 }
750 }
751
752 if (execute_program)
753 {
754 /*
755 * Execute the Jam STAPL ByteCode program
756 */
757 exec_result = jbi_execute(file_buffer, file_length, workspace,
758 workspace_size, action, init_list, reset_jtag,
759 &error_address, &exit_code, &format_version);
760
761 if (exec_result == JBIC_SUCCESS)
762 {
763 if (format_version == 2)
764 {
765 switch (exit_code)
766 {
767 case 0: exit_string = "Success"; break;
768 case 1: exit_string = "Checking chain failure"; break;
769 case 2: exit_string = "Reading IDCODE failure"; break;
770 case 3: exit_string = "Reading USERCODE failure"; break;
771 case 4: exit_string = "Reading UESCODE failure"; break;
772 case 5: exit_string = "Entering ISP failure"; break;
773 case 6: exit_string = "Unrecognized device"; break;
774 case 7: exit_string = "Device revision is not supported"; break;
775 case 8: exit_string = "Erase failure"; break;
776 case 9: exit_string = "Device is not blank"; break;
777 case 10: exit_string = "Device programming failure"; break;
778 case 11: exit_string = "Device verify failure"; break;
779 case 12: exit_string = "Read failure"; break;
780 case 13: exit_string = "Calculating checksum failure"; break;
781 case 14: exit_string = "Setting security bit failure"; break;
782 case 15: exit_string = "Querying security bit failure"; break;
783 case 16: exit_string = "Exiting ISP failure"; break;
784 case 17: exit_string = "Performing system test failure"; break;
785 default: exit_string = "Unknown exit code"; break;
786 }
787 }
788 else
789 {
790 switch (exit_code)
791 {
792 case 0: exit_string = "Success"; break;
793 case 1: exit_string = "Illegal initialization values"; break;
794 case 2: exit_string = "Unrecognized device"; break;
795 case 3: exit_string = "Device revision is not supported"; break;
796 case 4: exit_string = "Device programming failure"; break;
797 case 5: exit_string = "Device is not blank"; break;
798 case 6: exit_string = "Device verify failure"; break;
799 case 7: exit_string = "SRAM configuration failure"; break;
800 default: exit_string = "Unknown exit code"; break;
801 }
802 }
803
804 printf("Exit code = %d... %s\n", exit_code, exit_string);
805 }
806 else if ((format_version == 2) &&
807 (exec_result == JBIC_ACTION_NOT_FOUND))
808 {
809 if ((action == NULL) || (*action == '\0'))
810 {
811 printf("Error: no action specified for Jam STAPL file.\nProgram terminated.\n");
812 }
813 else
814 {
815 printf("Error: action \"%s\" is not supported for this Jam STAPL file.\nProgram terminated.\n", action);
816 }
817 }
818 else if (exec_result < MAX_ERROR_CODE)
819 {
820 printf("Error at address %ld: %s.\nProgram terminated.\n",
821 error_address, error_text[exec_result]);
822 }
823 else
824 {
825 printf("Unknown error code %d\n", exec_result);
826 }
827 }
828 }
829 }
830
831 if (jtag_hardware_initialized) usb_blaster_quit();
832
833 if (workspace != NULL) jbi_free(workspace);
834 if (file_buffer != NULL) jbi_free(file_buffer);
835
836 return (exit_status);
837}
Note: See TracBrowser for help on using the repository browser.