Charles Hardin ckhardin at gmail.com Instead of stashing the context in a global...
[fw/openocd] / src / openocd.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
21 #define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "log.h"
28 #include "types.h"
29 #include "jtag.h"
30 #include "configuration.h"
31 #include "xsvf.h"
32 #include "target.h"
33 #include "flash.h"
34 #include "nand.h"
35 #include "pld.h"
36
37 #include "command.h"
38 #include "server.h"
39 #include "telnet_server.h"
40 #include "gdb_server.h"
41 #include "tcl_server.h"
42
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <strings.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <errno.h>
51
52 #ifdef _WIN32
53 #include <malloc.h>
54 #else
55 #include <alloca.h>
56 #endif
57
58 #ifdef __ECOS
59 /* Jim is provied by eCos */
60 #include <cyg/jimtcl/jim.h>
61 #else
62 #define JIM_EMBEDDED
63 #include "jim.h"
64 #endif
65
66 #include "replacements.h"
67
68
69 /* Give TELNET a way to find out what version this is */
70 int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
71 {
72         command_print(cmd_ctx, OPENOCD_VERSION);
73
74         return ERROR_OK;
75 }
76
77 static int daemon_startup = 0;
78
79 int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
80 {
81         if (argc==0)
82                 return ERROR_OK;
83         if (argc > 1 )
84                 return ERROR_COMMAND_SYNTAX_ERROR;
85         
86         daemon_startup = strcmp("reset", args[0])==0;
87         
88         command_print(cmd_ctx, OPENOCD_VERSION);
89
90         return ERROR_OK;
91 }
92
93 void exit_handler(void)
94 {
95         /* close JTAG interface */
96         if (jtag && jtag->quit)
97                 jtag->quit();
98 }
99
100 /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
101 int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
102 {
103         int retval;
104         static int initialized=0;
105         if (initialized)
106                 return ERROR_OK;
107         
108         initialized=1;
109         
110         atexit(exit_handler);
111         
112         if (target_init(cmd_ctx) != ERROR_OK)
113                 return ERROR_FAIL;
114         LOG_DEBUG("target init complete");
115
116         if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
117         {
118                 /* we must be able to set up the jtag interface */
119                 return retval;
120         }
121         LOG_DEBUG("jtag interface init complete");
122
123         /* Try to initialize & examine the JTAG chain at this point, but
124          * continue startup regardless */
125         if (jtag_init(cmd_ctx) == ERROR_OK)
126         {
127                 LOG_DEBUG("jtag init complete");
128                 if (target_examine(cmd_ctx) == ERROR_OK)
129                 {
130                         LOG_DEBUG("jtag examine complete");
131                 }
132         }
133         
134         if (flash_init_drivers(cmd_ctx) != ERROR_OK)
135                 return ERROR_FAIL;
136         LOG_DEBUG("flash init complete");
137
138         if (nand_init(cmd_ctx) != ERROR_OK)
139                 return ERROR_FAIL;
140         LOG_DEBUG("NAND init complete");
141
142         if (pld_init(cmd_ctx) != ERROR_OK)
143                 return ERROR_FAIL;
144         LOG_DEBUG("pld init complete");
145
146         /* initialize tcp server */
147         server_init();
148
149         /* initialize telnet subsystem */
150         telnet_init("Open On-Chip Debugger");
151         gdb_init();
152         tcl_init(); /* allows tcl to just connect without going thru telnet */
153
154         return ERROR_OK;
155 }
156
157 Jim_Interp *interp;
158
159 static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 val)
160 {
161         char *namebuf;
162         Jim_Obj *nameObjPtr, *valObjPtr;
163         int result;
164
165         namebuf = alloc_printf("%s(%d)", varname, idx);
166         if (!namebuf)
167                 return JIM_ERR;
168         
169         nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
170         valObjPtr = Jim_NewIntObj(interp, val);
171         if (!nameObjPtr || !valObjPtr)
172         {
173                 free(namebuf);
174                 return JIM_ERR;
175         }
176
177         Jim_IncrRefCount(nameObjPtr);
178         Jim_IncrRefCount(valObjPtr);
179         result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
180         Jim_DecrRefCount(interp, nameObjPtr);
181         Jim_DecrRefCount(interp, valObjPtr);
182         free(namebuf);
183         /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
184         return result;
185 }
186
187 static int Jim_Command_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
188 {
189         target_t *target;
190         command_context_t *context;
191         long l;
192         u32 width;
193         u32 len;
194         u32 addr;
195         u32 count;
196         u32 v;
197         const char *varname;
198         u8 buffer[4096];
199         int  i, n, e, retval;
200
201         /* argv[1] = name of array to receive the data
202          * argv[2] = desired width
203          * argv[3] = memory address 
204          * argv[4] = count of times to read
205          */
206         if (argc != 5) {
207                 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
208                 return JIM_ERR;
209         }
210         varname = Jim_GetString(argv[1], &len);
211         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
212
213         e = Jim_GetLong(interp, argv[2], &l);
214         width = l;
215         if (e != JIM_OK) {
216                 return e;
217         }
218         
219         e = Jim_GetLong(interp, argv[3], &l);
220         addr = l;
221         if (e != JIM_OK) {
222                 return e;
223         }
224         e = Jim_GetLong(interp, argv[4], &l);
225         len = l;
226         if (e != JIM_OK) {
227                 return e;
228         }
229         switch (width) {
230                 case 8:
231                         width = 1;
232                         break;
233                 case 16:
234                         width = 2;
235                         break;
236                 case 32:
237                         width = 4;
238                         break;
239                 default:
240                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
241                         Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
242                         return JIM_ERR;
243         }
244         if (len == 0) {
245                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
246                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
247                 return JIM_ERR;
248         }
249         if ((addr + (len * width)) < addr) {
250                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
251                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
252                 return JIM_ERR;
253         }
254         /* absurd transfer size? */
255         if (len > 65536) {
256                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
257                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
258                 return JIM_ERR;
259         }               
260                 
261         if ((width == 1) ||
262                 ((width == 2) && ((addr & 1) == 0)) ||
263                 ((width == 4) && ((addr & 3) == 0))) {
264                 /* all is well */
265         } else {
266                 char buf[100];
267                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
268                 sprintf(buf, "mem2array address: 0x%08x is not aligned for %d byte reads", addr, width); 
269                 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
270                 return JIM_ERR;
271         }
272
273         context = Jim_GetAssocData(interp, "context");
274         if (context == NULL)
275         {
276                 LOG_ERROR("mem2array: no command context");
277                 return JIM_ERR;
278         }
279         target = get_current_target(context);
280         if (target == NULL)
281         {
282                 LOG_ERROR("mem2array: no current target");
283                 return JIM_ERR;
284         }
285         
286         /* Transfer loop */
287
288         /* index counter */
289         n = 0;
290         /* assume ok */
291         e = JIM_OK;
292         while (len) {
293                 /* Slurp... in buffer size chunks */
294                 
295                 count = len; /* in objects.. */
296                 if (count > (sizeof(buffer)/width)) {
297                         count = (sizeof(buffer)/width);
298                 }
299                 
300                 retval = target->type->read_memory( target, addr, width, count, buffer );
301                 if (retval != ERROR_OK) {
302                         /* BOO !*/
303                         LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
304                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
305                         Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
306                         e = JIM_ERR;
307                         len = 0;
308                 } else {
309                         v = 0; /* shut up gcc */
310                         for (i = 0 ;i < count ;i++, n++) {
311                                 switch (width) {
312                                         case 4:
313                                                 v = target_buffer_get_u32(target, &buffer[i*width]);
314                                                 break;
315                                         case 2:
316                                                 v = target_buffer_get_u16(target, &buffer[i*width]);
317                                                 break;
318                                         case 1:
319                                                 v = buffer[i] & 0x0ff;
320                                                 break;
321                                 }
322                                 new_int_array_element(interp, varname, n, v);
323                         }
324                         len -= count;
325                 }
326         }
327         
328         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
329
330         return JIM_OK;
331 }
332
333 static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 *val)
334 {
335         char *namebuf;
336         Jim_Obj *nameObjPtr, *valObjPtr;
337         int result;
338         long l;
339
340         namebuf = alloc_printf("%s(%d)", varname, idx);
341         if (!namebuf)
342                 return JIM_ERR;
343
344         nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
345         if (!nameObjPtr)
346         {
347                 free(namebuf);
348                 return JIM_ERR;
349         }
350
351         Jim_IncrRefCount(nameObjPtr);
352         valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
353         Jim_DecrRefCount(interp, nameObjPtr);
354         free(namebuf);
355         if (valObjPtr == NULL)
356                 return JIM_ERR;
357
358         result = Jim_GetLong(interp, valObjPtr, &l);
359         /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
360         *val = l;
361         return result;
362 }
363
364 static int Jim_Command_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
365 {
366         target_t *target;
367         command_context_t *context;
368         long l;
369         u32 width;
370         u32 len;
371         u32 addr;
372         u32 count;
373         u32 v;
374         const char *varname;
375         u8 buffer[4096];
376         int  i, n, e, retval;
377
378         /* argv[1] = name of array to get the data
379          * argv[2] = desired width
380          * argv[3] = memory address 
381          * argv[4] = count to write
382          */
383         if (argc != 5) {
384                 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
385                 return JIM_ERR;
386         }
387         varname = Jim_GetString(argv[1], &len);
388         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
389
390         e = Jim_GetLong(interp, argv[2], &l);
391         width = l;
392         if (e != JIM_OK) {
393                 return e;
394         }
395         
396         e = Jim_GetLong(interp, argv[3], &l);
397         addr = l;
398         if (e != JIM_OK) {
399                 return e;
400         }
401         e = Jim_GetLong(interp, argv[4], &l);
402         len = l;
403         if (e != JIM_OK) {
404                 return e;
405         }
406         switch (width) {
407                 case 8:
408                         width = 1;
409                         break;
410                 case 16:
411                         width = 2;
412                         break;
413                 case 32:
414                         width = 4;
415                         break;
416                 default:
417                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
418                         Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
419                         return JIM_ERR;
420         }
421         if (len == 0) {
422                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
423                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
424                 return JIM_ERR;
425         }
426         if ((addr + (len * width)) < addr) {
427                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
428                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
429                 return JIM_ERR;
430         }
431         /* absurd transfer size? */
432         if (len > 65536) {
433                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
434                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
435                 return JIM_ERR;
436         }               
437                 
438         if ((width == 1) ||
439                 ((width == 2) && ((addr & 1) == 0)) ||
440                 ((width == 4) && ((addr & 3) == 0))) {
441                 /* all is well */
442         } else {
443                 char buf[100];
444                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
445                 sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", addr, width); 
446                 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
447                 return JIM_ERR;
448         }
449
450         context = Jim_GetAssocData(interp, "context");
451         if (context == NULL)
452         {
453                 LOG_ERROR("array2mem: no command context");
454                 return JIM_ERR;
455         }
456         target = get_current_target(context);
457         if (target == NULL)
458         {
459                 LOG_ERROR("array2mem: no current target");
460                 return JIM_ERR;
461         }
462         
463         /* Transfer loop */
464
465         /* index counter */
466         n = 0;
467         /* assume ok */
468         e = JIM_OK;
469         while (len) {
470                 /* Slurp... in buffer size chunks */
471                 
472                 count = len; /* in objects.. */
473                 if (count > (sizeof(buffer)/width)) {
474                         count = (sizeof(buffer)/width);
475                 }
476
477                 v = 0; /* shut up gcc */
478                 for (i = 0 ;i < count ;i++, n++) {
479                         get_int_array_element(interp, varname, n, &v);
480                         switch (width) {
481                         case 4:
482                                 target_buffer_set_u32(target, &buffer[i*width], v);
483                                 break;
484                         case 2:
485                                 target_buffer_set_u16(target, &buffer[i*width], v);
486                                 break;
487                         case 1:
488                                 buffer[i] = v & 0x0ff;
489                                 break;
490                         }
491                 }
492                 len -= count;
493
494                 retval = target->type->write_memory(target, addr, width, count, buffer);
495                 if (retval != ERROR_OK) {
496                         /* BOO !*/
497                         LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
498                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
499                         Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
500                         e = JIM_ERR;
501                         len = 0;
502                 }
503         }
504         
505         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
506
507         return JIM_OK;
508 }
509
510
511
512 /* find full path to file */
513 static int Jim_Command_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
514 {
515         if (argc != 2)
516                 return JIM_ERR;
517         const char *file = Jim_GetString(argv[1], NULL);
518         char *full_path = find_file(file);
519         if (full_path == NULL)
520                 return JIM_ERR;
521         Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
522         free(full_path);
523         
524         Jim_SetResult(interp, result);
525         return JIM_OK;
526 }
527
528 static int Jim_Command_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
529 {
530         if (argc != 2)
531                 return JIM_ERR;
532         const char *str = Jim_GetString(argv[1], NULL);
533         LOG_USER("%s", str);
534         return JIM_OK;
535 }
536
537
538
539 static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
540 {
541         size_t nbytes;
542         const char *ptr;
543         Jim_Interp *interp;
544         command_context_t *context;
545
546         /* make it a char easier to read code */
547         ptr = _ptr;
548         interp = cookie;
549         nbytes = size * n;
550         if (ptr == NULL || interp == NULL || nbytes == 0) {
551                 return 0;
552         }
553
554         context = Jim_GetAssocData(interp, "context");
555         if (context == NULL)
556         {
557                 LOG_ERROR("openocd_jim_fwrite: no command context");
558                 /* TODO: Where should this go? */               
559                 return n;
560         }
561
562         /* do we have to chunk it? */
563         if (ptr[nbytes] == 0)
564         {
565                 /* no it is a C style string */
566                 command_output_text(context, ptr);
567                 return strlen(ptr);
568         }
569         /* GRR we must chunk - not null terminated */
570         while (nbytes) {
571                 char chunk[128+1];
572                 int x;
573
574                 x = nbytes;
575                 if (x > 128) {
576                         x = 128;
577                 }
578                 /* copy it */
579                 memcpy(chunk, ptr, x);
580                 /* terminate it */
581                 chunk[n] = 0;
582                 /* output it */
583                 command_output_text(context, chunk);
584                 ptr += x;
585                 nbytes -= x;
586         }
587         
588         return n;
589 }
590
591 static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
592 {
593         /* TCL wants to read... tell him no */
594         return 0;
595 }
596
597 static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
598 {
599         char *cp;
600         int n;
601         Jim_Interp *interp;
602         command_context_t *context;
603
604         n = -1;
605         interp = cookie;
606         if (interp == NULL)
607                 return n;
608
609         context = Jim_GetAssocData(interp, "context");
610         if (context == NULL)
611         {
612                 LOG_ERROR("openocd_jim_vfprintf: no command context");
613                 return n;
614         }
615
616         cp = alloc_vprintf(fmt, ap);
617         if (cp)
618         {
619                 command_output_text(context, cp);
620                 n = strlen(cp);
621                 free(cp);
622         }
623         return n;
624 }
625
626 static int openocd_jim_fflush(void *cookie)
627 {
628         /* nothing to flush */
629         return 0;
630 }
631
632 static char* openocd_jim_fgets(char *s, int size, void *cookie)
633 {
634         /* not supported */
635         errno = ENOTSUP;
636         return NULL;
637 }
638
639 void add_jim(const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
640 {
641         Jim_CreateCommand(interp, name, cmd, NULL, NULL);
642         
643         /* FIX!!! it would be prettier to invoke add_help_text... 
644         accumulate help text in Tcl helptext list.  */
645     Jim_Obj *helptext=Jim_GetGlobalVariableStr(interp, "ocd_helptext", JIM_ERRMSG);
646     if (Jim_IsShared(helptext))
647         helptext = Jim_DuplicateObj(interp, helptext);
648     
649         Jim_Obj *cmd_entry=Jim_NewListObj(interp, NULL, 0);
650         
651         Jim_Obj *cmd_list=Jim_NewListObj(interp, NULL, 0);
652         Jim_ListAppendElement(interp, cmd_list, Jim_NewStringObj(interp, name, -1));
653         
654         Jim_ListAppendElement(interp, cmd_entry, cmd_list);
655         Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
656         Jim_ListAppendElement(interp, helptext, cmd_entry);
657 }
658
659 extern unsigned const char startup_tcl[];
660
661 void initJim(void)
662 {
663         Jim_CreateCommand(interp, "openocd_find", Jim_Command_find, NULL, NULL);
664         Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
665         Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
666         Jim_CreateCommand(interp, "array2mem", Jim_Command_array2mem, NULL, NULL );
667
668         /* Set Jim's STDIO */
669         interp->cookie_stdin = interp;
670         interp->cookie_stdout = interp;
671         interp->cookie_stderr = interp;
672         interp->cb_fwrite = openocd_jim_fwrite;
673         interp->cb_fread = openocd_jim_fread ;
674         interp->cb_vfprintf = openocd_jim_vfprintf;
675         interp->cb_fflush = openocd_jim_fflush;
676         interp->cb_fgets = openocd_jim_fgets;
677         
678         add_default_dirs();
679         
680         if (Jim_Eval(interp, startup_tcl)==JIM_ERR)
681         {
682                 LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD compile time)");
683                 Jim_PrintErrorMessage(interp);
684                 exit(-1);
685         }
686 }
687
688 command_context_t *setup_command_handler(void)
689 {
690         command_context_t *cmd_ctx;
691         
692         cmd_ctx = command_init();
693         
694         register_command(cmd_ctx, NULL, "version", handle_version_command,
695                                          COMMAND_EXEC, "show OpenOCD version");
696         register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, 
697                         "deprecated - use \"init\" and \"reset\" at end of startup script instead");
698         
699         /* register subsystem commands */
700         server_register_commands(cmd_ctx);
701         telnet_register_commands(cmd_ctx);
702         gdb_register_commands(cmd_ctx);
703         tcl_register_commands(cmd_ctx); /* tcl server commands */
704         log_register_commands(cmd_ctx);
705         jtag_register_commands(cmd_ctx);
706         xsvf_register_commands(cmd_ctx);
707         target_register_commands(cmd_ctx);
708         flash_register_commands(cmd_ctx);
709         nand_register_commands(cmd_ctx);
710         pld_register_commands(cmd_ctx);
711         
712         if (log_init(cmd_ctx) != ERROR_OK)
713         {
714                 exit(-1);
715         }
716         LOG_DEBUG("log init complete");
717
718         LOG_OUTPUT( OPENOCD_VERSION "\n" );
719         
720         register_command(cmd_ctx, NULL, "init", handle_init_command,
721                                          COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
722
723         return cmd_ctx;
724 }
725
726 /* normally this is the main() function entry, but if OpenOCD is linked
727  * into application, then this fn will not be invoked, but rather that
728  * application will have it's own implementation of main(). */
729 int openocd_main(int argc, char *argv[])
730 {
731 #ifdef JIM_EMBEDDED
732         Jim_InitEmbedded();
733         /* Create an interpreter */
734         interp = Jim_CreateInterp();
735         /* Add all the Jim core commands */
736         Jim_RegisterCoreCommands(interp);
737 #endif
738         
739         initJim();
740         
741         /* initialize commandline interface */
742         command_context_t *cmd_ctx;
743         cmd_ctx=setup_command_handler();
744         
745         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
746         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
747         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
748         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
749         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
750         LOG_OUTPUT( "$URL$\n");
751         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
752         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
753         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
754         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
755         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
756
757         command_context_mode(cmd_ctx, COMMAND_CONFIG);
758         command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
759
760         if (parse_cmdline_args(cmd_ctx, argc, argv) != ERROR_OK)
761                 return EXIT_FAILURE;
762         
763         if (parse_config_file(cmd_ctx) != ERROR_OK)
764                 return EXIT_FAILURE;
765
766         command_context_mode(cmd_ctx, COMMAND_EXEC);
767         if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
768                 return EXIT_FAILURE;
769         
770         if (daemon_startup)
771                 command_run_line(cmd_ctx, "reset");
772         
773         /* handle network connections */
774         server_loop(cmd_ctx);
775
776         /* shut server down */
777         server_quit();
778
779         unregister_all_commands(cmd_ctx);
780         
781         /* free commandline interface */
782         command_done(cmd_ctx);
783
784         return EXIT_SUCCESS;
785 }