]> git.sur5r.net Git - openocd/blob - src/ecosboard.c
44c0f0b9bf6d25b00a826064ffaff5374eb8f0a6
[openocd] / src / ecosboard.c
1 /***************************************************************************\r
2  *   Copyright (C) 2007-2008 by Ã˜yvind Harboe                              *\r
3  *                                                                         *\r
4  *   This program is free software; you can redistribute it and/or modify  *\r
5  *   it under the terms of the GNU General Public License as published by  *\r
6  *   the Free Software Foundation; either version 2 of the License, or     *\r
7  *   (at your option) any later version.                                   *\r
8  *                                                                         *\r
9  *   This program is distributed in the hope that it will be useful,       *\r
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
12  *   GNU General Public License for more details.                          *\r
13  *                                                                         *\r
14  *   You should have received a copy of the GNU General Public License     *\r
15  *   along with this program; if not, write to the                         *\r
16  *   Free Software Foundation, Inc.,                                       *\r
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
18  ***************************************************************************/\r
19 \r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include "log.h"\r
25 #include "types.h"\r
26 #include "jtag.h"\r
27 #include "configuration.h"\r
28 #include "xsvf.h"\r
29 #include "target.h"\r
30 #include "flash.h"\r
31 #include "nand.h"\r
32 #include "pld.h"\r
33 \r
34 #include "command.h"\r
35 #include "server.h"\r
36 #include "telnet_server.h"\r
37 #include "gdb_server.h"\r
38 \r
39 #include <time_support.h>\r
40 #include <sys/time.h>\r
41 #include <sys/types.h>\r
42 #include <strings.h>\r
43 #include <stdio.h>\r
44 #include <stdlib.h>\r
45 #include <string.h>\r
46 #include <unistd.h>\r
47 #include <errno.h>\r
48 \r
49 #include <cyg/io/flash.h>\r
50 #include <pkgconf/fs_jffs2.h>   // Address of JFFS2\r
51 #include <network.h>\r
52 \r
53 #include <fcntl.h>\r
54 #include <sys/stat.h>\r
55 #include <cyg/fileio/fileio.h>\r
56 #include <dirent.h>\r
57 #include <cyg/athttpd/http.h>\r
58 #include <cyg/athttpd/socket.h>\r
59 #include <cyg/athttpd/handler.h>\r
60 #include <cyg/athttpd/cgi.h>\r
61 #include <cyg/athttpd/forms.h>\r
62 #include <cyg/hal/hal_diag.h>\r
63 #include <cyg/kernel/kapi.h>\r
64 #include <cyg/io/serialio.h>\r
65 #include <cyg/io/io.h>\r
66 #include <netinet/tcp.h>\r
67 #include "rom.h"\r
68 #include <sys/ioctl.h>\r
69 #include <sys/socket.h>\r
70 #include <netinet/in.h>\r
71 #include <net/if.h>\r
72 #include <arpa/inet.h>\r
73 #include <sys/types.h>\r
74 #include <sys/socket.h>\r
75 #include <netdb.h>\r
76 #include <netinet/in.h>\r
77 #include <unistd.h>\r
78 #include <arpa/inet.h>\r
79 #include <stdio.h>\r
80 #include <ifaddrs.h>\r
81 #include <string.h>\r
82 \r
83 #include <unistd.h>\r
84 #include <stdio.h>\r
85 #define MAX_IFS 64\r
86 #if defined(CYGPKG_NET_FREEBSD_STACK)\r
87 #include <tftp_support.h>\r
88 /* posix compatibility broken*/\r
89 struct tftpd_fileops fileops =\r
90 {\r
91         (int (*)(const char *, int))open,\r
92         close,\r
93         (int (*)(int, const void *, int))write,\r
94         ( int (*)(int, void *, int))read\r
95 };\r
96 \r
97 #endif\r
98 \r
99 #define ZYLIN_VERSION "1.42"\r
100 #define ZYLIN_DATE __DATE__\r
101 #define ZYLIN_TIME __TIME__\r
102 #define ZYLIN_OPENOCD 921\r
103 #define ZYLIN_OPENOCD_VERSION "Zylin JTAG ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE " " ZYLIN_TIME\r
104 #define ZYLIN_CONFIG_DIR "/config/settings"\r
105 \r
106 void diag_write(char *buf, int len)\r
107 {\r
108         int j;\r
109         for (j = 0; j < len; j++)\r
110         {\r
111                 diag_printf("%c", buf[j]);\r
112         }\r
113 }\r
114 \r
115 static bool serialLog = true;\r
116 static bool writeLog = true;\r
117 \r
118 \r
119 struct FastLoad\r
120 {\r
121         u32 address;\r
122         u8 *data;\r
123         int length;\r
124 \r
125 };\r
126 \r
127 static int fastload_num;\r
128 static struct FastLoad *fastload;\r
129 \r
130 static void free_fastload()\r
131 {\r
132         if (fastload!=NULL)\r
133         {\r
134                 int i;\r
135                 for (i=0; i<fastload_num; i++)\r
136                 {\r
137                         if (fastload[i].data)\r
138                                 free(fastload[i].data);\r
139                 }\r
140                 free(fastload);\r
141                 fastload=NULL;\r
142         }\r
143 }\r
144 \r
145 \r
146 int handle_fast_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
147 {\r
148         u8 *buffer;\r
149         u32 buf_cnt;\r
150         u32 image_size;\r
151         u32 min_address=0;\r
152         u32 max_address=0xffffffff;\r
153         int i;\r
154         int retval;\r
155 \r
156         image_t image;\r
157 \r
158         duration_t duration;\r
159         char *duration_text;\r
160 \r
161         if ((argc < 1)||(argc > 5))\r
162         {\r
163                 return ERROR_COMMAND_SYNTAX_ERROR;\r
164         }\r
165 \r
166         /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */\r
167         if (argc >= 2)\r
168         {\r
169                 image.base_address_set = 1;\r
170                 image.base_address = strtoul(args[1], NULL, 0);\r
171         }\r
172         else\r
173         {\r
174                 image.base_address_set = 0;\r
175         }\r
176 \r
177 \r
178         image.start_address_set = 0;\r
179 \r
180         if (argc>=4)\r
181         {\r
182                 min_address=strtoul(args[3], NULL, 0);\r
183         }\r
184         if (argc>=5)\r
185         {\r
186                 max_address=strtoul(args[4], NULL, 0)+min_address;\r
187         }\r
188 \r
189         if (min_address>max_address)\r
190         {\r
191                 return ERROR_COMMAND_SYNTAX_ERROR;\r
192         }\r
193 \r
194         duration_start_measure(&duration);\r
195 \r
196         if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)\r
197         {\r
198                 return ERROR_OK;\r
199         }\r
200 \r
201         image_size = 0x0;\r
202         retval = ERROR_OK;\r
203         fastload_num=image.num_sections;\r
204         fastload=(struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections);\r
205         if (fastload==NULL)\r
206         {\r
207                 image_close(&image);\r
208                 return ERROR_FAIL;\r
209         }\r
210         memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections);\r
211         for (i = 0; i < image.num_sections; i++)\r
212         {\r
213                 buffer = malloc(image.sections[i].size);\r
214                 if (buffer == NULL)\r
215                 {\r
216                         command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size);\r
217                         break;\r
218                 }\r
219 \r
220                 if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)\r
221                 {\r
222                         free(buffer);\r
223                         break;\r
224                 }\r
225 \r
226                 u32 offset=0;\r
227                 u32 length=buf_cnt;\r
228 \r
229 \r
230                 /* DANGER!!! beware of unsigned comparision here!!! */\r
231 \r
232                 if ((image.sections[i].base_address+buf_cnt>=min_address)&&\r
233                                 (image.sections[i].base_address<max_address))\r
234                 {\r
235                         if (image.sections[i].base_address<min_address)\r
236                         {\r
237                                 /* clip addresses below */\r
238                                 offset+=min_address-image.sections[i].base_address;\r
239                                 length-=offset;\r
240                         }\r
241 \r
242                         if (image.sections[i].base_address+buf_cnt>max_address)\r
243                         {\r
244                                 length-=(image.sections[i].base_address+buf_cnt)-max_address;\r
245                         }\r
246 \r
247                         fastload[i].address=image.sections[i].base_address+offset;\r
248                         fastload[i].data=malloc(length);\r
249                         if (fastload[i].data==NULL)\r
250                         {\r
251                                 free(buffer);\r
252                                 break;\r
253                         }\r
254                         memcpy(fastload[i].data, buffer+offset, length);\r
255                         fastload[i].length=length;\r
256 \r
257                         image_size += length;\r
258                         command_print(cmd_ctx, "%u byte written at address 0x%8.8x", length, image.sections[i].base_address+offset);\r
259                 }\r
260 \r
261                 free(buffer);\r
262         }\r
263 \r
264         duration_stop_measure(&duration, &duration_text);\r
265         if (retval==ERROR_OK)\r
266         {\r
267                 command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text);\r
268         }\r
269         free(duration_text);\r
270 \r
271         image_close(&image);\r
272 \r
273         if (retval!=ERROR_OK)\r
274         {\r
275                 free_fastload();\r
276         }\r
277 \r
278         return retval;\r
279 }\r
280 \r
281 int handle_fast_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
282 {\r
283         if (argc>0)\r
284                 return ERROR_COMMAND_SYNTAX_ERROR;\r
285         if (fastload==NULL)\r
286         {\r
287                 LOG_ERROR("No image in memory");\r
288                 return ERROR_FAIL;\r
289         }\r
290         int i;\r
291         int ms=timeval_ms();\r
292         int size=0;\r
293         for (i=0; i<fastload_num;i++)\r
294         {\r
295                 int retval;\r
296                 target_t *target = get_current_target(cmd_ctx);\r
297                 if ((retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data)) != ERROR_OK)\r
298                 {\r
299                         return retval;\r
300                 }\r
301                 size+=fastload[i].length;\r
302         }\r
303         int after=timeval_ms();\r
304         command_print(cmd_ctx, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0));\r
305         return ERROR_OK;\r
306 }\r
307 \r
308 \r
309 /* Give TELNET a way to find out what version this is */\r
310 int handle_zy1000_version_command(struct command_context_s *cmd_ctx, char *cmd,\r
311                 char **args, int argc)\r
312 {\r
313         if (argc > 1)\r
314         {\r
315                 return ERROR_COMMAND_SYNTAX_ERROR;\r
316         }\r
317         if (argc == 0)\r
318         {\r
319                 command_print(cmd_ctx, ZYLIN_OPENOCD_VERSION);\r
320         } else if (strcmp("openocd", args[0])==0)\r
321         {\r
322                 command_print(cmd_ctx, "%d", ZYLIN_OPENOCD);\r
323         } else if (strcmp("zy1000", args[0])==0)\r
324         {\r
325                 command_print(cmd_ctx, "%s", ZYLIN_VERSION);\r
326         } else if (strcmp("date", args[0])==0)\r
327         {\r
328                 command_print(cmd_ctx, "%s", ZYLIN_DATE);\r
329         } else\r
330         {\r
331                 return ERROR_COMMAND_SYNTAX_ERROR;\r
332         }\r
333 \r
334         return ERROR_OK;\r
335 }\r
336 \r
337 extern flash_driver_t *flash_drivers[];\r
338 extern target_type_t *target_types[];\r
339 \r
340 #ifdef CYGPKG_PROFILE_GPROF\r
341 #include <cyg/profile/profile.h>\r
342 \r
343 extern char _stext, _etext; // Defined by the linker\r
344 \r
345 void start_profile(void)\r
346 {\r
347         // This starts up the system-wide profiling, gathering\r
348         // profile information on all of the code, with a 16 byte\r
349         // "bucket" size, at a rate of 100us/profile hit.\r
350         // Note: a bucket size of 16 will give pretty good function\r
351         //       resolution.  Much smaller and the buffer becomes\r
352         //       much too large for very little gain.\r
353         // Note: a timer period of 100us is also a reasonable\r
354         //       compromise.  Any smaller and the overhead of\r
355         //       handling the timter (profile) interrupt could\r
356         //       swamp the system.  A fast processor might get\r
357         //       by with a smaller value, but a slow one could\r
358         //       even be swamped by this value.  If the value is\r
359         //       too large, the usefulness of the profile is reduced.\r
360 \r
361         // no more interrupts than 1/10ms.\r
362         //    profile_on(&_stext, &_etext, 16, 10000); // DRAM\r
363         //profile_on((void *)0, (void *)0x40000, 16, 10000); // SRAM\r
364         profile_on(0, &_etext, 16, 10000); // SRAM & DRAM\r
365 }\r
366 #endif\r
367 \r
368 // launch GDB server if a config file exists\r
369 bool zylinjtag_parse_config_file(struct command_context_s *cmd_ctx, const char *config_file_name)\r
370 {\r
371         bool foundFile = false;\r
372         FILE *config_file = NULL;\r
373         command_print(cmd_ctx, "executing config file %s", config_file_name);\r
374         config_file = fopen(config_file_name, "r");\r
375         if (config_file)\r
376         {\r
377                 fclose(config_file);\r
378                 int retval;\r
379                 retval = command_run_linef(cmd_ctx, "script %s", config_file_name);\r
380                 if (retval == ERROR_OK)\r
381                 {\r
382                         foundFile = true;\r
383                 }\r
384                 else\r
385                 {\r
386                         command_print(cmd_ctx, "Failed executing %s %d", config_file_name, retval);\r
387                 }\r
388         }\r
389         else\r
390         {\r
391                 command_print(cmd_ctx, "No %s found", config_file_name);\r
392         }\r
393 \r
394         return foundFile;\r
395 }\r
396 \r
397 extern int eth0_up;\r
398 static FILE *log;\r
399 \r
400 static char reboot_stack[2048];\r
401 \r
402 \r
403 static void\r
404 zylinjtag_reboot(cyg_addrword_t data)\r
405 {\r
406         serialLog = true;\r
407         diag_printf("Rebooting in 100 ticks..\n");\r
408         cyg_thread_delay(100);\r
409         diag_printf("Unmounting /config..\n");\r
410         umount("/config");\r
411         diag_printf("Rebooting..\n");\r
412         HAL_PLATFORM_RESET();\r
413 }\r
414 static cyg_thread zylinjtag_thread_object;\r
415 static cyg_handle_t zylinjtag_thread_handle;\r
416 \r
417 void reboot(void)\r
418 {\r
419     cyg_thread_create(1,\r
420                       zylinjtag_reboot,\r
421                       (cyg_addrword_t)0,\r
422                       "reboot Thread",\r
423                       (void *)reboot_stack,\r
424                       sizeof(reboot_stack),\r
425                       &zylinjtag_thread_handle,\r
426                       &zylinjtag_thread_object);\r
427         cyg_thread_resume(zylinjtag_thread_handle);\r
428 }\r
429 \r
430 int configuration_output_handler(struct command_context_s *context, const char* line)\r
431 {\r
432         diag_printf("%s", line);\r
433 \r
434         return ERROR_OK;\r
435 }\r
436 \r
437 int zy1000_configuration_output_handler_log(struct command_context_s *context, const char* line)\r
438 {\r
439         LOG_USER_N("%s", line);\r
440 \r
441         return ERROR_OK;\r
442 }\r
443 \r
444 int handle_rm_command(struct command_context_s *cmd_ctx, char *cmd,\r
445                 char **args, int argc)\r
446 {\r
447         if (argc != 1)\r
448         {\r
449                 command_print(cmd_ctx, "rm <filename>");\r
450                 return ERROR_INVALID_ARGUMENTS;\r
451         }\r
452 \r
453         if (unlink(args[0]) != 0)\r
454         {\r
455                 command_print(cmd_ctx, "failed: %d", errno);\r
456         }\r
457 \r
458         return ERROR_OK;\r
459 }\r
460 \r
461 int loadFile(const char *fileName, void **data, int *len);\r
462 \r
463 int handle_cat_command(struct command_context_s *cmd_ctx, char *cmd,\r
464                 char **args, int argc)\r
465 {\r
466         if (argc != 1)\r
467         {\r
468                 command_print(cmd_ctx, "cat <filename>");\r
469                 return ERROR_INVALID_ARGUMENTS;\r
470         }\r
471 \r
472         // NOTE!!! we only have line printing capability so we print the entire file as a single line.\r
473         void *data;\r
474         int len;\r
475 \r
476         int retval = loadFile(args[0], &data, &len);\r
477         if (retval == ERROR_OK)\r
478         {\r
479                 command_print(cmd_ctx, "%s", data);\r
480                 free(data);\r
481         }\r
482         else\r
483         {\r
484                 command_print(cmd_ctx, "%s not found %d", args[0], retval);\r
485         }\r
486 \r
487         return ERROR_OK;\r
488 }\r
489 int handle_trunc_command(struct command_context_s *cmd_ctx, char *cmd,\r
490                 char **args, int argc)\r
491 {\r
492         if (argc != 1)\r
493         {\r
494                 command_print(cmd_ctx, "trunc <filename>");\r
495                 return ERROR_INVALID_ARGUMENTS;\r
496         }\r
497 \r
498         FILE *config_file = NULL;\r
499         config_file = fopen(args[0], "w");\r
500         if (config_file != NULL)\r
501                 fclose(config_file);\r
502 \r
503         return ERROR_OK;\r
504 }\r
505 \r
506 \r
507 int handle_meminfo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
508 {\r
509         static int prev = 0;\r
510         struct mallinfo info;\r
511 \r
512         if (argc != 0)\r
513         {\r
514                 command_print(cmd_ctx, "meminfo");\r
515                 return ERROR_INVALID_ARGUMENTS;\r
516         }\r
517 \r
518         info = mallinfo();\r
519 \r
520         if (prev > 0)\r
521         {\r
522                 command_print(cmd_ctx, "Diff:            %d", prev - info.fordblks);\r
523         }\r
524         prev = info.fordblks;\r
525 \r
526         command_print(cmd_ctx, "Available ram:   %d", info.fordblks );\r
527 \r
528         return ERROR_OK;\r
529 }\r
530 \r
531 static bool savePower;\r
532 \r
533 static void setPower(bool power)\r
534 {\r
535         savePower = power;\r
536         if (power)\r
537         {\r
538                 HAL_WRITE_UINT32(0x08000014, 0x8);\r
539         } else\r
540         {\r
541                 HAL_WRITE_UINT32(0x08000010, 0x8);\r
542         }\r
543 }\r
544 \r
545 int handle_power_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
546 {\r
547         if (argc > 1)\r
548         {\r
549                 return ERROR_INVALID_ARGUMENTS;\r
550         }\r
551 \r
552         if (argc == 1)\r
553         {\r
554                 if (strcmp(args[0], "on") == 0)\r
555                 {\r
556                         setPower(1);\r
557                 }\r
558                 else if (strcmp(args[0], "off") == 0)\r
559                 {\r
560                         setPower(0);\r
561                 } else\r
562                 {\r
563                         command_print(cmd_ctx, "arg is \"on\" or \"off\"");\r
564                         return ERROR_INVALID_ARGUMENTS;\r
565                 }\r
566         }\r
567 \r
568         command_print(cmd_ctx, "Target power %s", savePower ? "on" : "off");\r
569 \r
570         return ERROR_OK;\r
571 }\r
572 \r
573 int handle_append_command(struct command_context_s *cmd_ctx, char *cmd,\r
574                 char **args, int argc)\r
575 {\r
576         if (argc < 1)\r
577         {\r
578                 command_print(cmd_ctx,\r
579                                 "append <filename> [<string1>, [<string2>, ...]]");\r
580                 return ERROR_INVALID_ARGUMENTS;\r
581         }\r
582 \r
583         FILE *config_file = NULL;\r
584         config_file = fopen(args[0], "a");\r
585         if (config_file != NULL)\r
586         {\r
587                 int i;\r
588                 fseek(config_file, 0, SEEK_END);\r
589 \r
590                 for (i = 1; i < argc; i++)\r
591                 {\r
592                         fwrite(args[i], strlen(args[i]), 1, config_file);\r
593                         if (i != argc - 1)\r
594                         {\r
595                                 fwrite(" ", 1, 1, config_file);\r
596                         }\r
597                 }\r
598                 fwrite("\n", 1, 1, config_file);\r
599                 fclose(config_file);\r
600         }\r
601 \r
602         return ERROR_OK;\r
603 }\r
604 \r
605 extern int telnet_socket;\r
606 \r
607 int readMore(int fd, void *data, int length)\r
608 {\r
609         /* used in select() */\r
610         fd_set read_fds;\r
611 \r
612         /* monitor sockets for acitvity */\r
613         int fd_max = 1;\r
614         FD_ZERO(&read_fds);\r
615         /* listen for new connections */\r
616         FD_SET(fd, &read_fds);\r
617 \r
618         // Maximum 5 seconds.\r
619         struct timeval tv;\r
620         tv.tv_sec = 5;\r
621         tv.tv_usec = 0;\r
622 \r
623         int retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);\r
624         if (retval == 0)\r
625         {\r
626                 diag_printf("Timed out waiting for binary payload\n");\r
627                 return -1;\r
628         }\r
629         if (retval != 1)\r
630                 return -1;\r
631 \r
632         return read_socket(fd, data, length);\r
633 }\r
634 \r
635 int readAll(int fd, void *data, int length)\r
636 {\r
637         int pos = 0;\r
638         for (;;)\r
639         {\r
640                 int actual = readMore(fd, ((char *) data) + pos, length - pos);\r
641                 //              diag_printf("Read %d bytes(pos=%d, length=%d)\n", actual, pos, length);\r
642                 if (actual <= 0)\r
643                         return -1;\r
644                 pos += actual;\r
645                 if (pos == length)\r
646                         break;\r
647         }\r
648         return length;\r
649 }\r
650 \r
651 int handle_peek_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
652 {\r
653         cyg_uint32 value;\r
654         if (argc != 1)\r
655         {\r
656                 return ERROR_INVALID_ARGUMENTS;\r
657         }\r
658         HAL_READ_UINT32(strtoul(args[0], NULL, 0), value);\r
659         command_print(cmd_ctx, "0x%x : 0x%x", strtoul(args[0], NULL, 0), value);\r
660         return ERROR_OK;\r
661 }\r
662 \r
663 int handle_poke_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
664 {\r
665         if (argc != 2)\r
666         {\r
667                 return ERROR_INVALID_ARGUMENTS;\r
668         }\r
669         HAL_WRITE_UINT32(strtoul(args[0], NULL, 0), strtoul(args[1], NULL, 0));\r
670         return ERROR_OK;\r
671 }\r
672 \r
673 int handle_cp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
674 {\r
675         if (argc != 2)\r
676         {\r
677                 return ERROR_INVALID_ARGUMENTS;\r
678         }\r
679 \r
680         // NOTE!!! we only have line printing capability so we print the entire file as a single line.\r
681         void *data;\r
682         int len;\r
683 \r
684         int retval = loadFile(args[0], &data, &len);\r
685         if (retval != ERROR_OK)\r
686                 return retval;\r
687 \r
688         FILE *f = fopen(args[1], "wb");\r
689         if (f == NULL)\r
690                 retval = ERROR_INVALID_ARGUMENTS;\r
691 \r
692         int pos = 0;\r
693         for (;;)\r
694         {\r
695                 int chunk = len - pos;\r
696                 static const int maxChunk = 512 * 1024; // ~1/sec\r
697                 if (chunk > maxChunk)\r
698                 {\r
699                         chunk = maxChunk;\r
700                 }\r
701 \r
702                 if ((retval==ERROR_OK)&&(fwrite(((char *)data)+pos, 1, chunk, f)!=chunk))\r
703                         retval = ERROR_INVALID_ARGUMENTS;\r
704 \r
705                 if (retval != ERROR_OK)\r
706                 {\r
707                         break;\r
708                 }\r
709 \r
710                 command_print(cmd_ctx, "%d", len - pos);\r
711 \r
712                 pos += chunk;\r
713 \r
714                 if (pos == len)\r
715                         break;\r
716         }\r
717 \r
718         if (retval == ERROR_OK)\r
719         {\r
720                 command_print(cmd_ctx, "Copied %s to %s", args[0], args[1]);\r
721         } else\r
722         {\r
723                 command_print(cmd_ctx, "Failed: %d", retval);\r
724         }\r
725 \r
726         if (data != NULL)\r
727                 free(data);\r
728         if (f != NULL)\r
729                 fclose(f);\r
730 \r
731         if (retval != ERROR_OK)\r
732                 unlink(args[1]);\r
733 \r
734         return retval;\r
735 }\r
736 \r
737 #ifdef CYGPKG_PROFILE_GPROF\r
738 extern void start_profile();\r
739 \r
740 int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
741 {\r
742         command_print(cmd_ctx, "Profiling started");\r
743         start_profile();\r
744         return ERROR_OK;\r
745 }\r
746 \r
747 #endif\r
748 \r
749 externC void phi_init_all_network_interfaces();\r
750 \r
751 command_context_t *cmd_ctx;\r
752 \r
753 static bool webRunning = false;\r
754 \r
755 void keep_webserver()\r
756 {\r
757         // Target initialisation is only attempted at startup, so we sleep forever and\r
758         // let the http server bail us out(i.e. get config files set up).\r
759         diag_printf("OpenOCD has invoked exit().\n"\r
760                 "Use web server to correct any configuration settings and reboot.\n");\r
761         if (!webRunning)\r
762                 reboot();\r
763 \r
764         // exit() will terminate the current thread and we we'll then sleep eternally or\r
765         // we'll have a reboot scheduled.\r
766 }\r
767 \r
768 extern void printDccChar(char c);\r
769 \r
770 static char logBuffer[128 * 1024];\r
771 static const int logSize = sizeof(logBuffer);\r
772 int writePtr = 0;\r
773 int logCount = 0;\r
774 \r
775 void _zylinjtag_diag_write_char(char c, void **param)\r
776 {\r
777         if (writeLog)\r
778         {\r
779                 logBuffer[writePtr] = c;\r
780                 writePtr = (writePtr + 1) % logSize;\r
781                 logCount++;\r
782         }\r
783         if (serialLog)\r
784         {\r
785                 if (c == '\n')\r
786                 {\r
787                         HAL_DIAG_WRITE_CHAR('\r');\r
788                 }\r
789                 HAL_DIAG_WRITE_CHAR(c);\r
790         }\r
791 \r
792         printDccChar(c);\r
793 }\r
794 \r
795 #define SHOW_RESULT(a, b) diag_printf(#a " failed %d\n", (int)b)\r
796 \r
797 #define IOSIZE 512\r
798 static void copyfile(char *name2, char *name1)\r
799 {\r
800 \r
801         int err;\r
802         char buf[IOSIZE];\r
803         int fd1, fd2;\r
804         ssize_t done, wrote;\r
805 \r
806         fd1 = open(name1, O_WRONLY | O_CREAT);\r
807         if (fd1 < 0)\r
808                 SHOW_RESULT( open, fd1 );\r
809 \r
810         fd2 = open(name2, O_RDONLY);\r
811         if (fd2 < 0)\r
812                 SHOW_RESULT( open, fd2 );\r
813 \r
814         for (;;)\r
815         {\r
816                 done = read(fd2, buf, IOSIZE );\r
817                 if (done < 0)\r
818                 {\r
819                         SHOW_RESULT( read, done );\r
820                         break;\r
821                 }\r
822 \r
823         if( done == 0 ) break;\r
824 \r
825                 wrote = write(fd1, buf, done);\r
826         if( wrote != done ) SHOW_RESULT( write, wrote );\r
827 \r
828         if( wrote != done ) break;\r
829         }\r
830 \r
831         err = close(fd1);\r
832     if( err < 0 ) SHOW_RESULT( close, err );\r
833 \r
834         err = close(fd2);\r
835     if( err < 0 ) SHOW_RESULT( close, err );\r
836 \r
837 }\r
838 static void copydir(char *name)\r
839 {\r
840         int err;\r
841         DIR *dirp;\r
842 \r
843         mkdir("/ram/cgi", 0777);\r
844 \r
845         dirp = opendir(name);\r
846     if( dirp == NULL ) SHOW_RESULT( opendir, -1 );\r
847 \r
848         for (;;)\r
849         {\r
850                 struct dirent *entry = readdir(dirp);\r
851 \r
852                 if (entry == NULL)\r
853                         break;\r
854 \r
855                 if (strcmp(entry->d_name, ".") == 0)\r
856                         continue;\r
857                 if (strcmp(entry->d_name, "..") == 0)\r
858                         continue;\r
859 \r
860                 bool isDir = false;\r
861                 struct stat buf;\r
862                 char fullPath[PATH_MAX];\r
863                 strncpy(fullPath, name, PATH_MAX);\r
864                 strcat(fullPath, "/");\r
865                 strncat(fullPath, entry->d_name, PATH_MAX - strlen(fullPath));\r
866 \r
867                 if (stat(fullPath, &buf) == -1)\r
868                 {\r
869                         diag_printf("unable to read status from %s", fullPath);\r
870                         break;\r
871                 }\r
872                 isDir = S_ISDIR(buf.st_mode) != 0;\r
873 \r
874                 if (isDir)\r
875                         continue;\r
876 \r
877                 //        diag_printf("<INFO>: entry %14s",entry->d_name);\r
878                 char fullname[PATH_MAX];\r
879                 char fullname2[PATH_MAX];\r
880 \r
881                 strcpy(fullname, name);\r
882                 strcat(fullname, entry->d_name);\r
883 \r
884                 strcpy(fullname2, "/ram/cgi/");\r
885                 strcat(fullname2, entry->d_name);\r
886                 //        diag_printf("from %s to %s\n", fullname, fullname2);\r
887                 copyfile(fullname, fullname2);\r
888 \r
889                 //       diag_printf("\n");\r
890         }\r
891 \r
892         err = closedir(dirp);\r
893     if( err < 0 ) SHOW_RESULT( stat, err );\r
894 }\r
895 \r
896 #if 0\r
897 MTAB_ENTRY( romfs_mte1,\r
898                 "/rom",\r
899                 "romfs",\r
900                 "",\r
901                 (CYG_ADDRWORD) &filedata[0] );\r
902 #endif\r
903 \r
904 void openocd_sleep_prelude()\r
905 {\r
906         cyg_mutex_unlock(&httpstate.jim_lock);\r
907 }\r
908 \r
909 void openocd_sleep_postlude()\r
910 {\r
911         cyg_mutex_lock(&httpstate.jim_lock);\r
912 }\r
913 \r
914 static int\r
915 zylinjtag_Jim_Command_rm(Jim_Interp *interp,\r
916                                    int argc,\r
917                 Jim_Obj * const *argv)\r
918 {\r
919         int del;\r
920         if (argc != 2)\r
921         {\r
922                 Jim_WrongNumArgs(interp, 1, argv, "rm ?dirorfile?");\r
923                 return JIM_ERR;\r
924         }\r
925 \r
926         del = 0;\r
927         if (unlink(Jim_GetString(argv[1], NULL)) == 0)\r
928                 del = 1;\r
929         if (rmdir(Jim_GetString(argv[1], NULL)) == 0)\r
930                 del = 1;\r
931 \r
932         return del ? JIM_OK : JIM_ERR;\r
933 }\r
934 \r
935 static int\r
936 zylinjtag_Jim_Command_ls(Jim_Interp *interp,\r
937                                    int argc,\r
938                 Jim_Obj * const *argv)\r
939 {\r
940         if (argc != 2)\r
941         {\r
942                 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");\r
943                 return JIM_ERR;\r
944         }\r
945 \r
946         char *name = (char*) Jim_GetString(argv[1], NULL);\r
947 \r
948         DIR *dirp = NULL;\r
949         dirp = opendir(name);\r
950         if (dirp == NULL)\r
951         {\r
952                 return JIM_ERR;\r
953         }\r
954         Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);\r
955 \r
956         for (;;)\r
957         {\r
958                 struct dirent *entry = NULL;\r
959                 entry = readdir(dirp);\r
960                 if (entry == NULL)\r
961                         break;\r
962 \r
963                 if ((strcmp(".", entry->d_name)==0)||(strcmp("..", entry->d_name)==0))\r
964                         continue;\r
965 \r
966         Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));\r
967         }\r
968         closedir(dirp);\r
969 \r
970         Jim_SetResult(interp, objPtr);\r
971 \r
972         return JIM_OK;\r
973 }\r
974 \r
975 \r
976 static int\r
977 zylinjtag_Jim_Command_getmem(Jim_Interp *interp,\r
978                                    int argc,\r
979                 Jim_Obj * const *argv)\r
980 {\r
981         if (argc != 3)\r
982         {\r
983                 Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");\r
984                 return JIM_ERR;\r
985         }\r
986 \r
987         long address;\r
988         long length;\r
989         if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)\r
990                 return JIM_ERR;\r
991         if (Jim_GetLong(interp, argv[2], &length) != JIM_OK)\r
992                 return JIM_ERR;\r
993 \r
994         if (length < 0 && length > (4096 * 1024))\r
995         {\r
996                 Jim_WrongNumArgs(interp, 1, argv, "getmem ?dir?");\r
997                 return JIM_ERR;\r
998         }\r
999 \r
1000         void *mem = malloc(length);\r
1001         if (mem == NULL)\r
1002                 return JIM_ERR;\r
1003 \r
1004         target_t *target = get_current_target(cmd_ctx);\r
1005 \r
1006         int retval;\r
1007         int size = 1;\r
1008         int count = length;\r
1009         if ((address % 4 == 0) && (count % 4 == 0))\r
1010         {\r
1011                 size = 4;\r
1012                 count /= 4;\r
1013         }\r
1014 \r
1015         if ((retval  = target->type->read_memory(target, address, size, count, mem)) != ERROR_OK)\r
1016         {\r
1017                 free(mem);\r
1018                 return JIM_ERR;\r
1019         }\r
1020 \r
1021         Jim_Obj *objPtr = Jim_NewStringObj(interp, mem, length);\r
1022         Jim_SetResult(interp, objPtr);\r
1023 \r
1024         free(mem);\r
1025 \r
1026         return JIM_OK;\r
1027 }\r
1028 \r
1029 static int\r
1030 zylinjtag_Jim_Command_peek(Jim_Interp *interp,\r
1031                                    int argc,\r
1032                 Jim_Obj * const *argv)\r
1033 {\r
1034         if (argc != 2)\r
1035         {\r
1036                 Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");\r
1037                 return JIM_ERR;\r
1038         }\r
1039 \r
1040         long address;\r
1041         if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)\r
1042                 return JIM_ERR;\r
1043 \r
1044         int value = *((volatile int *) address);\r
1045 \r
1046         Jim_SetResult(interp, Jim_NewIntObj(interp, value));\r
1047 \r
1048         return JIM_OK;\r
1049 }\r
1050 \r
1051 static int\r
1052 zylinjtag_Jim_Command_poke(Jim_Interp *interp,\r
1053                                    int argc,\r
1054                 Jim_Obj * const *argv)\r
1055 {\r
1056         if (argc != 3)\r
1057         {\r
1058                 Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");\r
1059                 return JIM_ERR;\r
1060         }\r
1061 \r
1062         long address;\r
1063         if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)\r
1064                 return JIM_ERR;\r
1065         long value;\r
1066         if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)\r
1067                 return JIM_ERR;\r
1068 \r
1069         *((volatile int *) address) = value;\r
1070 \r
1071         return JIM_OK;\r
1072 }\r
1073 \r
1074 \r
1075 \r
1076 static int\r
1077 zylinjtag_Jim_Command_flash(Jim_Interp *interp,\r
1078                                    int argc,\r
1079                 Jim_Obj * const *argv)\r
1080 {\r
1081         int retval;\r
1082         u32 base = 0;\r
1083         flash_bank_t *t = get_flash_bank_by_num_noprobe(0);\r
1084         if (t != NULL)\r
1085         {\r
1086                 base = t->base;\r
1087                 retval = JIM_OK;\r
1088     } else\r
1089         {\r
1090                 retval = JIM_ERR;\r
1091         }\r
1092 \r
1093         if (retval == JIM_OK)\r
1094         {\r
1095                 Jim_SetResult(interp, Jim_NewIntObj(interp, base));\r
1096         }\r
1097 \r
1098         return retval;\r
1099 }\r
1100 \r
1101 \r
1102 \r
1103 \r
1104 \r
1105 static int\r
1106 zylinjtag_Jim_Command_log(Jim_Interp *interp,\r
1107                                    int argc,\r
1108                 Jim_Obj * const *argv)\r
1109 {\r
1110         Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);\r
1111 \r
1112         if (logCount >= logSize)\r
1113         {\r
1114         Jim_AppendString(httpstate.jim_interp, tclOutput, logBuffer+logCount%logSize, logSize-logCount%logSize);\r
1115         }\r
1116         Jim_AppendString(httpstate.jim_interp, tclOutput, logBuffer, writePtr);\r
1117 \r
1118         Jim_SetResult(interp, tclOutput);\r
1119         return JIM_OK;\r
1120 }\r
1121 \r
1122 static int\r
1123 zylinjtag_Jim_Command_reboot(Jim_Interp *interp,\r
1124                                    int argc,\r
1125                 Jim_Obj * const *argv)\r
1126 {\r
1127         reboot();\r
1128         return JIM_OK;\r
1129 }\r
1130 \r
1131 static int\r
1132 zylinjtag_Jim_Command_mac(Jim_Interp *interp,\r
1133                                    int argc,\r
1134                 Jim_Obj * const *argv)\r
1135 {\r
1136         int s;\r
1137         struct ifreq ifr;\r
1138         s = socket(AF_INET, SOCK_DGRAM, 0);\r
1139         if (s >= 0)\r
1140         {\r
1141                 strcpy(ifr.ifr_name, "eth0");\r
1142                 int res;\r
1143                 res = ioctl(s, SIOCGIFHWADDR, &ifr);\r
1144                 close(s);\r
1145 \r
1146                 if (res < 0)\r
1147                 {\r
1148                         return JIM_OK;\r
1149                 }\r
1150         }\r
1151 \r
1152         Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);\r
1153 \r
1154         char hwaddr[512];\r
1155         sprintf(hwaddr, "%02x:%02x:%02x:%02x:%02x:%02x",\r
1156                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[0],\r
1157                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[1],\r
1158                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[2],\r
1159                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[3],\r
1160                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[4],\r
1161                         (int) ((unsigned char *) &ifr.ifr_hwaddr.sa_data)[5]);\r
1162 \r
1163         Jim_AppendString(httpstate.jim_interp, tclOutput, hwaddr, strlen(hwaddr));\r
1164 \r
1165         Jim_SetResult(interp, tclOutput);\r
1166 \r
1167         return JIM_OK;\r
1168 }\r
1169 \r
1170 static int\r
1171 zylinjtag_Jim_Command_ip(Jim_Interp *interp,\r
1172                                    int argc,\r
1173                 Jim_Obj * const *argv)\r
1174 {\r
1175         Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);\r
1176 \r
1177         struct ifaddrs *ifa = NULL, *ifp = NULL;\r
1178 \r
1179         if (getifaddrs(&ifp) < 0)\r
1180         {\r
1181                 return JIM_ERR;\r
1182         }\r
1183 \r
1184         for (ifa = ifp; ifa; ifa = ifa->ifa_next)\r
1185         {\r
1186                 char ip[200];\r
1187                 socklen_t salen;\r
1188 \r
1189                 if (ifa->ifa_addr->sa_family == AF_INET)\r
1190                         salen = sizeof(struct sockaddr_in);\r
1191                 else if (ifa->ifa_addr->sa_family == AF_INET6)\r
1192                         salen = sizeof(struct sockaddr_in6);\r
1193                 else\r
1194                         continue;\r
1195 \r
1196                 if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,\r
1197                                 NI_NUMERICHOST) < 0)\r
1198                 {\r
1199                         continue;\r
1200                 }\r
1201 \r
1202                 Jim_AppendString(httpstate.jim_interp, tclOutput, ip, strlen(ip));\r
1203                 break;\r
1204 \r
1205         }\r
1206 \r
1207         freeifaddrs(ifp);\r
1208 \r
1209         Jim_SetResult(interp, tclOutput);\r
1210 \r
1211         return JIM_OK;\r
1212 }\r
1213 \r
1214 extern Jim_Interp *interp;\r
1215 \r
1216 static void zylinjtag_startNetwork()\r
1217 {\r
1218         // Bring TCP/IP up immediately before we're ready to accept commands.\r
1219         //\r
1220         // That is as soon as a PING responds, we're accepting telnet sessions.\r
1221 #if defined(CYGPKG_NET_FREEBSD_STACK)\r
1222         phi_init_all_network_interfaces();\r
1223 #else\r
1224         lwip_init();\r
1225 #endif\r
1226         if (!eth0_up)\r
1227         {\r
1228                 diag_printf("Network not up and running\n");\r
1229                 exit(-1);\r
1230         }\r
1231 #if defined(CYGPKG_NET_FREEBSD_STACK)\r
1232         /*start TFTP*/\r
1233         tftpd_start(69, &fileops);\r
1234 #endif\r
1235 \r
1236         cyg_httpd_init_tcl_interpreter();\r
1237 \r
1238         interp = httpstate.jim_interp;\r
1239 \r
1240     Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log, NULL, NULL);\r
1241     Jim_CreateCommand(httpstate.jim_interp, "reboot", zylinjtag_Jim_Command_reboot, NULL, NULL);\r
1242     Jim_CreateCommand(httpstate.jim_interp, "peek", zylinjtag_Jim_Command_peek, NULL, NULL);\r
1243     Jim_CreateCommand(httpstate.jim_interp, "zy1000_flash", zylinjtag_Jim_Command_flash, NULL, NULL);\r
1244     Jim_CreateCommand(httpstate.jim_interp, "poke", zylinjtag_Jim_Command_poke, NULL, NULL);\r
1245     Jim_CreateCommand(httpstate.jim_interp, "ls", zylinjtag_Jim_Command_ls, NULL, NULL);\r
1246     Jim_CreateCommand(httpstate.jim_interp, "getmem", zylinjtag_Jim_Command_getmem, NULL, NULL);\r
1247     Jim_CreateCommand(httpstate.jim_interp, "mac", zylinjtag_Jim_Command_mac, NULL, NULL);\r
1248     Jim_CreateCommand(httpstate.jim_interp, "ip", zylinjtag_Jim_Command_ip, NULL, NULL);\r
1249     Jim_CreateCommand(httpstate.jim_interp, "rm", zylinjtag_Jim_Command_rm, NULL, NULL);\r
1250 \r
1251         cyg_httpd_start();\r
1252 \r
1253         webRunning = true;\r
1254 \r
1255         diag_printf("Web server running\n");\r
1256 }\r
1257 \r
1258 static bool readPowerDropout()\r
1259 {\r
1260         cyg_uint32 state;\r
1261         // sample and clear power dropout\r
1262         HAL_WRITE_UINT32(0x08000010, 0x80);\r
1263         HAL_READ_UINT32(0x08000010, state);\r
1264         bool powerDropout;\r
1265         powerDropout = (state & 0x80) != 0;\r
1266         return powerDropout;\r
1267 }\r
1268 \r
1269 bool readSRST()\r
1270 {\r
1271         cyg_uint32 state;\r
1272         // sample and clear SRST sensing\r
1273         HAL_WRITE_UINT32(0x08000010, 0x00000040);\r
1274         HAL_READ_UINT32(0x08000010, state);\r
1275         bool srstAsserted;\r
1276         srstAsserted = (state & 0x40) != 0;\r
1277         return srstAsserted;\r
1278 }\r
1279 \r
1280 // every 300ms we check for reset & powerdropout and issue a "reset halt" if\r
1281 // so.\r
1282 \r
1283 \r
1284 static int sense_handler(void *priv)\r
1285 {\r
1286         struct command_context_s *cmd_ctx;\r
1287         cmd_ctx = (struct command_context_s *) priv;\r
1288 \r
1289         static bool prevSrstAsserted = false;\r
1290         static bool prevPowerdropout = false;\r
1291 \r
1292         bool powerDropout;\r
1293         powerDropout = readPowerDropout();\r
1294 \r
1295         bool powerRestored;\r
1296         powerRestored = prevPowerdropout && !powerDropout;\r
1297         if (powerRestored)\r
1298         {\r
1299                 LOG_USER("Sensed power restore.");\r
1300         }\r
1301 \r
1302         cyg_tick_count_t current = cyg_current_time();\r
1303         static cyg_tick_count_t lastPower = 0;\r
1304         bool waitMore = lastPower + 200 > current;\r
1305         if (powerDropout && !waitMore)\r
1306         {\r
1307                 LOG_USER("Sensed power dropout.");\r
1308                 lastPower = current;\r
1309         }\r
1310 \r
1311         bool srstAsserted = readSRST();\r
1312 \r
1313         bool srstDeasserted;\r
1314         srstDeasserted = prevSrstAsserted && !srstAsserted;\r
1315 \r
1316         static cyg_tick_count_t lastSrst = 0;\r
1317         waitMore = lastSrst + 200 > current;\r
1318         if (srstDeasserted && !waitMore)\r
1319         {\r
1320                 LOG_USER("Sensed nSRST deasserted");\r
1321                 lastSrst = current;\r
1322         }\r
1323 \r
1324         if (!prevSrstAsserted && srstAsserted)\r
1325         {\r
1326                 LOG_USER("Sensed nSRST asserted");\r
1327         }\r
1328 \r
1329         prevSrstAsserted = srstAsserted;\r
1330         prevPowerdropout = powerDropout;\r
1331 \r
1332         if (srstDeasserted || powerRestored)\r
1333         {\r
1334                 /* Other than logging the event we can't do anything here.\r
1335                  * Issuing a reset is a particularly bad idea as we might\r
1336                  * be inside a reset already.\r
1337                  */\r
1338         }\r
1339 \r
1340         return ERROR_OK;\r
1341 }\r
1342 \r
1343 \r
1344 \r
1345 static void\r
1346 print_exception_handler(cyg_addrword_t data, cyg_code_t exception, cyg_addrword_t info)\r
1347 {\r
1348         writeLog = false;\r
1349         serialLog = true;\r
1350         char *infoStr = "unknown";\r
1351         switch (exception)\r
1352         {\r
1353         case CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION:\r
1354                 infoStr = "undefined instruction";\r
1355                 break;\r
1356         case CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT:\r
1357                 infoStr = "software interrupt";\r
1358                 break;\r
1359         case CYGNUM_HAL_VECTOR_ABORT_PREFETCH:\r
1360                 infoStr = "abort prefetch";\r
1361                 break;\r
1362         case CYGNUM_HAL_VECTOR_ABORT_DATA:\r
1363                 infoStr = "abort data";\r
1364                 break;\r
1365         default:\r
1366                 break;\r
1367         }\r
1368 \r
1369         diag_printf("Exception: %08x(%s) %08x\n", exception, infoStr, info);\r
1370 \r
1371         diag_printf("Dumping log\n---\n");\r
1372         if (logCount >= logSize)\r
1373         {\r
1374                 diag_write(logBuffer + logCount % logSize, logSize - logCount % logSize);\r
1375         }\r
1376         diag_write(logBuffer, writePtr);\r
1377 \r
1378         diag_printf("---\nLogdump complete.\n");\r
1379         diag_printf("Exception: %08x(%s) %08x\n", exception, infoStr, info);\r
1380         diag_printf("\n---\nRebooting\n");\r
1381         HAL_PLATFORM_RESET();\r
1382 \r
1383 }\r
1384 \r
1385 static void setHandler(cyg_code_t exception)\r
1386 {\r
1387         cyg_exception_handler_t *old_handler;\r
1388         cyg_addrword_t old_data;\r
1389 \r
1390         cyg_exception_set_handler(exception,\r
1391         print_exception_handler,\r
1392         0,\r
1393         &old_handler,\r
1394         &old_data);\r
1395 }\r
1396 \r
1397 static cyg_thread zylinjtag_uart_thread_object;\r
1398 static cyg_handle_t zylinjtag_uart_thread_handle;\r
1399 static char uart_stack[4096];\r
1400 \r
1401 static char forwardBuffer[1024]; // NB! must be smaller than a TCP/IP packet!!!!!\r
1402 static char backwardBuffer[1024];\r
1403 \r
1404 static cyg_io_handle_t serial_handle;\r
1405 \r
1406 void setNoDelay(int session, int flag)\r
1407 {\r
1408 #if 1\r
1409         // This decreases latency dramatically for e.g. GDB load which\r
1410         // does not have a sliding window protocol\r
1411         //\r
1412         // Can cause *lots* of TCP/IP packets to be sent and it would have\r
1413         // to be enabled/disabled on the fly to avoid the CPU being\r
1414         // overloaded...\r
1415         setsockopt(session, /* socket affected */\r
1416         IPPROTO_TCP, /* set option at TCP level */\r
1417         TCP_NODELAY, /* name of option */\r
1418         (char *) &flag, /* the cast is historical\r
1419          cruft */\r
1420         sizeof(int)); /* length of option value */\r
1421 #endif\r
1422 }\r
1423 \r
1424 struct\r
1425 {\r
1426         int req;\r
1427         int actual;\r
1428         int req2;\r
1429         int actual2;\r
1430 } tcpipSent[512 * 1024];\r
1431 int cur;\r
1432 \r
1433 static void\r
1434 zylinjtag_uart(cyg_addrword_t data)\r
1435 {\r
1436         int so_reuseaddr_option = 1;\r
1437 \r
1438         int fd;\r
1439         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)\r
1440         {\r
1441                 LOG_ERROR("error creating socket: %s", strerror(errno));\r
1442                 exit(-1);\r
1443         }\r
1444 \r
1445         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));\r
1446 \r
1447         struct sockaddr_in sin;\r
1448         unsigned int address_size;\r
1449         address_size = sizeof(sin);\r
1450         memset(&sin, 0, sizeof(sin));\r
1451         sin.sin_family = AF_INET;\r
1452         sin.sin_addr.s_addr = INADDR_ANY;\r
1453         sin.sin_port = htons(5555);\r
1454 \r
1455         if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1)\r
1456         {\r
1457                 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));\r
1458                 exit(-1);\r
1459         }\r
1460 \r
1461         if (listen(fd, 1) == -1)\r
1462         {\r
1463                 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));\r
1464                 exit(-1);\r
1465         }\r
1466         //      socket_nonblock(fd);\r
1467 \r
1468 \r
1469         for (;;)\r
1470         {\r
1471                 int session = accept(fd, (struct sockaddr *) &sin, &address_size);\r
1472                 if (session < 0)\r
1473                 {\r
1474                         continue;\r
1475                 }\r
1476 \r
1477                 setNoDelay(session, 1);\r
1478                 int oldopts = fcntl(session, F_GETFL, 0);\r
1479                 fcntl(session, F_SETFL, oldopts | O_NONBLOCK); //\r
1480 \r
1481                 int serHandle = open("/dev/ser0", O_RDWR | O_NONBLOCK);\r
1482                 if (serHandle < 0)\r
1483                 {\r
1484                         close(session);\r
1485                         continue;\r
1486                 }\r
1487 \r
1488                 start_profile();\r
1489                 int actual = 0;\r
1490                 int actual2 = 0;\r
1491                 int pos, pos2;\r
1492                 pos = 0;\r
1493                 pos2 = 0;\r
1494                 cur = 0;\r
1495                 for (;;)\r
1496                 {\r
1497                         fd_set write_fds;\r
1498                         fd_set read_fds;\r
1499                         FD_ZERO(&write_fds);\r
1500                         FD_ZERO(&read_fds);\r
1501                         int fd_max = -1;\r
1502                         FD_SET(session, &read_fds);\r
1503                         fd_max = session;\r
1504                         FD_SET(serHandle, &read_fds);\r
1505                         if (serHandle > fd_max)\r
1506                         {\r
1507                                 fd_max = serHandle;\r
1508                         }\r
1509                         /* Wait... */\r
1510 \r
1511                         cyg_thread_delay(5); // 50ms fixed delay to wait for data to be sent/received\r
1512                         if ((actual == 0) && (actual2 == 0))\r
1513                         {\r
1514                                 int retval = select(fd_max + 1, &read_fds, NULL, NULL, NULL);\r
1515                                 if (retval <= 0)\r
1516                                 {\r
1517                                         break;\r
1518                                 }\r
1519                         }\r
1520 \r
1521                         if (actual2 <= 0)\r
1522                         {\r
1523                                 memset(backwardBuffer, 's', sizeof(backwardBuffer));\r
1524                                 actual2=read(serHandle, backwardBuffer, sizeof(backwardBuffer));\r
1525                                 if (actual2 < 0)\r
1526                                 {\r
1527                                         if (errno != EAGAIN)\r
1528                                         {\r
1529                                                 goto closeSession;\r
1530                                         }\r
1531                                         actual2 = 0;\r
1532                                 }\r
1533                                 pos2 = 0;\r
1534                         }\r
1535 \r
1536                         int x = actual2;\r
1537                         int y = 0;\r
1538                         if (actual2 > 0)\r
1539                         {\r
1540                                 int written = write(session, backwardBuffer + pos2, actual2);\r
1541                                 if (written <= 0)\r
1542                                         goto closeSession;\r
1543                                 actual2 -= written;\r
1544                                 pos2 += written;\r
1545                                 y = written;\r
1546                         }\r
1547 \r
1548                         if (FD_ISSET(session, &read_fds)&&(sizeof(forwardBuffer)>actual))\r
1549                         {\r
1550                                 // NB! Here it is important that we empty the TCP/IP read buffer\r
1551                                 // to make transmission tick right\r
1552                                 memmove(forwardBuffer, forwardBuffer + pos, actual);\r
1553                                 pos = 0;\r
1554                                 int t;\r
1555                                 // this will block if there is no data at all\r
1556                                 t=read_socket(session, forwardBuffer+actual, sizeof(forwardBuffer)-actual);\r
1557                                 if (t <= 0)\r
1558                                 {\r
1559                                         goto closeSession;\r
1560                                 }\r
1561                                 actual += t;\r
1562                         }\r
1563 \r
1564                         int x2 = actual;\r
1565                         int y2 = 0;\r
1566                         if (actual > 0)\r
1567                         {\r
1568                                 /* Do not put things into the serial buffer if it has something to send\r
1569                                  * as that can cause a single byte to be sent at the time.\r
1570                                  *\r
1571                                  *\r
1572                                  */\r
1573                                 int written = write(serHandle, forwardBuffer + pos, actual);\r
1574                                 if (written < 0)\r
1575                                 {\r
1576                                         if (errno != EAGAIN)\r
1577                                         {\r
1578                                                 goto closeSession;\r
1579                                         }\r
1580                                         // The serial buffer is full\r
1581                                         written = 0;\r
1582                                 } else\r
1583                                 {\r
1584                                         actual -= written;\r
1585                                         pos += written;\r
1586                                 }\r
1587                                 y2 = written;\r
1588                         }\r
1589                         if (cur < 1024)\r
1590                         {\r
1591                                 tcpipSent[cur].req = x;\r
1592                                 tcpipSent[cur].actual = y;\r
1593                                 tcpipSent[cur].req2 = x2;\r
1594                                 tcpipSent[cur].actual2 = y2;\r
1595                                 cur++;\r
1596                         }\r
1597 \r
1598                 }\r
1599             closeSession:\r
1600             close(session);\r
1601                 close(serHandle);\r
1602 \r
1603                 int i;\r
1604                 for (i = 0; i < 1024; i++)\r
1605                 {\r
1606                 diag_printf("%d %d %d %d\n", tcpipSent[i].req, tcpipSent[i].actual, tcpipSent[i].req2, tcpipSent[i].actual2);\r
1607 \r
1608                 }\r
1609         }\r
1610         close(fd);\r
1611 \r
1612 }\r
1613 \r
1614 void startUart(void)\r
1615 {\r
1616     cyg_thread_create(1,\r
1617                       zylinjtag_uart,\r
1618                       (cyg_addrword_t)0,\r
1619                       "uart thread",\r
1620                       (void *)uart_stack,\r
1621                       sizeof(uart_stack),\r
1622                       &zylinjtag_uart_thread_handle,\r
1623                       &zylinjtag_uart_thread_object);\r
1624         cyg_thread_set_priority(zylinjtag_uart_thread_handle, 1); // low priority as it sits in a busy loop\r
1625         cyg_thread_resume(zylinjtag_uart_thread_handle);\r
1626 }\r
1627 \r
1628 \r
1629 \r
1630 int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
1631 {\r
1632         if (argc != 1)\r
1633         {\r
1634                 command_print(cmd_ctx, "usage: uart <baudrate>");\r
1635                 return ERROR_INVALID_ARGUMENTS;\r
1636         }\r
1637 \r
1638         int baud = atol(args[0]);\r
1639 \r
1640         switch (baud)\r
1641         {\r
1642         case 9600:\r
1643                 baud = CYGNUM_SERIAL_BAUD_9600;\r
1644                 break;\r
1645         case 19200:\r
1646                 baud = CYGNUM_SERIAL_BAUD_19200;\r
1647                 break;\r
1648         case 38400:\r
1649                 baud = CYGNUM_SERIAL_BAUD_38400;\r
1650                 break;\r
1651         case 57600:\r
1652                 baud = CYGNUM_SERIAL_BAUD_57600;\r
1653                 break;\r
1654         case 115200:\r
1655                 baud = CYGNUM_SERIAL_BAUD_115200;\r
1656                 break;\r
1657         case 230400:\r
1658                 baud = CYGNUM_SERIAL_BAUD_230400;\r
1659                 break;\r
1660         default:\r
1661                 command_print(cmd_ctx, "unsupported baudrate");\r
1662                 return ERROR_INVALID_ARGUMENTS;\r
1663         }\r
1664 \r
1665         cyg_serial_info_t buf;\r
1666         cyg_uint32 len = 1;\r
1667         //get existing serial configuration\r
1668         len = sizeof(cyg_serial_info_t);\r
1669         int err;\r
1670         err = cyg_io_get_config(serial_handle, CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, &buf, &len);\r
1671         err = cyg_io_get_config(serial_handle, CYG_IO_GET_CONFIG_SERIAL_INFO, &buf, &len);\r
1672         if (err != ENOERR)\r
1673         {\r
1674                 command_print(cmd_ctx, "Failed to get serial port settings %d", err);\r
1675                 return ERROR_OK;\r
1676         }\r
1677         buf.baud = baud;\r
1678 \r
1679         err = cyg_io_set_config(serial_handle, CYG_IO_SET_CONFIG_SERIAL_INFO, &buf, &len);\r
1680         if (err != ENOERR)\r
1681         {\r
1682                 command_print(cmd_ctx, "Failed to set serial port settings %d", err);\r
1683                 return ERROR_OK;\r
1684         }\r
1685 \r
1686         return ERROR_OK;\r
1687 }\r
1688 \r
1689 bool logAllToSerial = false;\r
1690 \r
1691 /* boolean parameter stored on config */\r
1692 bool boolParam(char *var)\r
1693 {\r
1694         bool result = false;\r
1695         char *name = alloc_printf(ZYLIN_CONFIG_DIR "/%s", var);\r
1696         if (name == NULL)\r
1697                 return result;\r
1698 \r
1699         void *data;\r
1700         int len;\r
1701         if (loadFile(name, &data, &len) == ERROR_OK)\r
1702         {\r
1703                 if (len > 1)\r
1704                         len = 1;\r
1705                 result = strncmp((char *) data, "1", len) == 0;\r
1706                 free(data);\r
1707         }\r
1708         free(name);\r
1709         return result;\r
1710 }\r
1711 \r
1712 command_context_t *setup_command_handler();\r
1713 \r
1714 int add_default_dirs(void)\r
1715 {\r
1716         add_script_search_dir(ZYLIN_CONFIG_DIR);\r
1717         add_script_search_dir("/rom/lib/openocd");\r
1718         add_script_search_dir("/rom");\r
1719         return ERROR_OK;\r
1720 }\r
1721 \r
1722 int main(int argc, char *argv[])\r
1723 {\r
1724         setHandler(CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION);\r
1725         setHandler(CYGNUM_HAL_VECTOR_ABORT_PREFETCH);\r
1726         setHandler(CYGNUM_HAL_VECTOR_ABORT_DATA);\r
1727 \r
1728         int err;\r
1729         err = cyg_io_lookup("/dev/ser0", &serial_handle);\r
1730         if (err != ENOERR)\r
1731         {\r
1732                 diag_printf("/dev/ser0 not found\n");\r
1733                 reboot();\r
1734         }\r
1735 \r
1736         setPower(true); // on by default\r
1737 \r
1738         atexit(keep_webserver);\r
1739 \r
1740         err = mount("", "/ram", "ramfs");\r
1741         if (err < 0)\r
1742         {\r
1743                 diag_printf("unable to mount ramfs\n");\r
1744         }\r
1745         chdir("/ram");\r
1746 \r
1747         char address[16];\r
1748         sprintf(address, "%p", &filedata[0]);\r
1749         err = mount(address, "/rom", "romfs");\r
1750         if (err < 0)\r
1751         {\r
1752                 diag_printf("unable to mount /rom\n");\r
1753         }\r
1754 \r
1755         err = mount("", "/log", "logfs");\r
1756         if (err < 0)\r
1757         {\r
1758                 diag_printf("unable to mount logfs\n");\r
1759         }\r
1760 \r
1761         err = mount("", "/tftp", "tftpfs");\r
1762         if (err < 0)\r
1763         {\r
1764                 diag_printf("unable to mount logfs\n");\r
1765         }\r
1766 \r
1767         log = fopen("/log/log", "w");\r
1768         if (log == NULL)\r
1769         {\r
1770                 diag_printf("Could not open log file /ram/log\n");\r
1771                 exit(-1);\r
1772         }\r
1773 \r
1774         diag_init_putc(_zylinjtag_diag_write_char);\r
1775 \r
1776         // We want this in the log.\r
1777         diag_printf("Zylin ZY1000. Copyright Zylin AS 2007-2008.\n");\r
1778         diag_printf("%s\n", ZYLIN_OPENOCD_VERSION);\r
1779 \r
1780         copydir("/rom/");\r
1781 \r
1782         err = mount("/dev/flash1", "/config", "jffs2");\r
1783         if (err < 0)\r
1784         {\r
1785                 diag_printf("unable to mount jffs\n");\r
1786         }\r
1787 \r
1788 \r
1789         mkdir(ZYLIN_CONFIG_DIR, 0777);\r
1790         mkdir(ZYLIN_CONFIG_DIR "/target", 0777);\r
1791         mkdir(ZYLIN_CONFIG_DIR "/event", 0777);\r
1792 \r
1793         logAllToSerial = boolParam("logserial");\r
1794 \r
1795         // We need the network & web server in case there is something wrong with\r
1796         // the config files that invoke exit()\r
1797         zylinjtag_startNetwork();\r
1798 \r
1799         /* we're going to access the jim interpreter from here on... */\r
1800         openocd_sleep_postlude();\r
1801         startUart();\r
1802 \r
1803         add_default_dirs();\r
1804 \r
1805         /* initialize commandline interface */\r
1806         command_context_t *cmd_ctx;\r
1807         cmd_ctx = setup_command_handler();\r
1808         command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);\r
1809         command_context_mode(cmd_ctx, COMMAND_CONFIG);\r
1810 \r
1811 \r
1812         register_command(cmd_ctx, NULL, "zy1000_version", handle_zy1000_version_command,\r
1813                         COMMAND_EXEC, "show zy1000 version numbers");\r
1814 \r
1815         register_command(cmd_ctx, NULL, "rm", handle_rm_command, COMMAND_ANY,\r
1816                         "rm <filname>");\r
1817 \r
1818         register_command(cmd_ctx, NULL, "fast_load_image", handle_fast_load_image_command, COMMAND_ANY,\r
1819                         "same args as load_image, image stored in memory");\r
1820 \r
1821         register_command(cmd_ctx, NULL, "fast_load", handle_fast_load_command, COMMAND_ANY,\r
1822                         "loads active fast load image to current target");\r
1823 \r
1824         register_command(cmd_ctx, NULL, "cat", handle_cat_command, COMMAND_ANY,\r
1825                         "cat <filname>");\r
1826 \r
1827         register_command(cmd_ctx, NULL, "trunc", handle_trunc_command, COMMAND_ANY,\r
1828                         "trunc <filname>");\r
1829 \r
1830         register_command(cmd_ctx, NULL, "append_file", handle_append_command,\r
1831                         COMMAND_ANY, "append <filname>");\r
1832 \r
1833         register_command(cmd_ctx, NULL, "power", handle_power_command, COMMAND_ANY,\r
1834                         "power <on/off> - turn power switch to target on/off. No arguments - print status.");\r
1835 \r
1836         register_command(cmd_ctx, NULL, "meminfo", handle_meminfo_command,\r
1837                         COMMAND_ANY, "meminfo");\r
1838 \r
1839         register_command(cmd_ctx, NULL, "cp", handle_cp_command,\r
1840                                          COMMAND_ANY, "cp <from> <to>");\r
1841 \r
1842 #ifdef CYGPKG_PROFILE_GPROF\r
1843         register_command(cmd_ctx, NULL, "ecosboard_profile", eCosBoard_handle_eCosBoard_profile_command,\r
1844                         COMMAND_ANY, NULL);\r
1845 #endif\r
1846         register_command(cmd_ctx, NULL, "uart", handle_uart_command,\r
1847                                          COMMAND_ANY, "uart <baud>  - forward uart on port 5555");\r
1848 \r
1849 \r
1850         int errVal;\r
1851         errVal = log_init(cmd_ctx);\r
1852         if (errVal != ERROR_OK)\r
1853         {\r
1854                 diag_printf("log_init() failed %d\n", errVal);\r
1855                 exit(-1);\r
1856         }\r
1857 \r
1858         set_log_output(cmd_ctx, log);\r
1859 \r
1860         LOG_DEBUG("log init complete");\r
1861 \r
1862         //      diag_printf("Executing config files\n");\r
1863 \r
1864         if (logAllToSerial)\r
1865         {\r
1866                 diag_printf(ZYLIN_CONFIG_DIR "/logserial=1 => sending log output to serial port using \"debug_level 3\" as default.\n");\r
1867                 command_run_line(cmd_ctx, "debug_level 3");\r
1868         }\r
1869 \r
1870         zylinjtag_parse_config_file(cmd_ctx, "/rom/openocd.cfg");\r
1871 \r
1872         target_register_timer_callback(sense_handler, 200, 1, cmd_ctx);\r
1873 \r
1874         // FIX!!!  Yuk!\r
1875         // diag_printf() is really invoked from many more places than we trust it\r
1876         // not to cause instabilities(e.g. invoking fputc() from an interrupt is *BAD*).\r
1877         //\r
1878         // Disabling it here is safe and gives us enough logged debug output for now. Crossing\r
1879         // fingers that it doesn't cause any crashes.\r
1880         diag_printf("Init complete, GDB & telnet servers launched.\n");\r
1881         command_set_output_handler(cmd_ctx, zy1000_configuration_output_handler_log, NULL);\r
1882         if (!logAllToSerial)\r
1883         {\r
1884                 serialLog = false;\r
1885         }\r
1886 \r
1887         /* handle network connections */\r
1888         server_loop(cmd_ctx);\r
1889         openocd_sleep_prelude();\r
1890 \r
1891         /* shut server down */\r
1892         server_quit();\r
1893 \r
1894         /* free commandline interface */\r
1895         command_done(cmd_ctx);\r
1896         umount("/config");\r
1897 \r
1898         exit(0);\r
1899         for (;;);\r
1900 }\r
1901 \r
1902 \r
1903 \r
1904 cyg_int32\r
1905 cyg_httpd_exec_cgi_tcl(char *file_name);\r
1906 cyg_int32 homeForm(CYG_HTTPD_STATE *p)\r
1907 {\r
1908         cyg_httpd_exec_cgi_tcl("/ram/cgi/index.tcl");\r
1909         return 0;\r
1910 }\r
1911 \r
1912 CYG_HTTPD_HANDLER_TABLE_ENTRY(root_label, "/", homeForm);\r
1913 \r
1914 CYG_HTTPD_MIME_TABLE_ENTRY(text_mime_label, "text", "text/plain");\r
1915 CYG_HTTPD_MIME_TABLE_ENTRY(bin_mime_label, "bin", "application/octet-stream");\r
1916 \r
1917 #include <pkgconf/system.h>\r
1918 #include <pkgconf/hal.h>\r
1919 #include <pkgconf/kernel.h>\r
1920 #include <pkgconf/io_fileio.h>\r
1921 #include <pkgconf/fs_rom.h>\r
1922 \r
1923 #include <cyg/kernel/ktypes.h>         // base kernel types\r
1924 #include <cyg/infra/cyg_trac.h>        // tracing macros\r
1925 #include <cyg/infra/cyg_ass.h>         // assertion macros\r
1926 #include <unistd.h>\r
1927 #include <sys/types.h>\r
1928 #include <fcntl.h>\r
1929 #include <sys/stat.h>\r
1930 #include <errno.h>\r
1931 #include <dirent.h>\r
1932 \r
1933 #include <stdarg.h>\r
1934 #include <stdio.h>\r
1935 #include <stdlib.h>\r
1936 #include <string.h>\r
1937 \r
1938 #include <cyg/fileio/fileio.h>\r
1939 \r
1940 #include <cyg/kernel/kapi.h>\r
1941 #include <cyg/infra/diag.h>\r
1942 \r
1943 //==========================================================================\r
1944 // Eventually we want to eXecute In Place from the ROM in a protected\r
1945 // environment, so we'll need executables to be aligned to a boundary\r
1946 // suitable for MMU protection. A suitable boundary would be the 4k\r
1947 // boundary in all the CPU architectures I am currently aware of.\r
1948 \r
1949 // Forward definitions\r
1950 \r
1951 // Filesystem operations\r
1952 static int tftpfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte);\r
1953 static int tftpfs_umount(cyg_mtab_entry *mte);\r
1954 static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,\r
1955                 int mode, cyg_file *fte);\r
1956 static int tftpfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);\r
1957 static int tftpfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);\r
1958 \r
1959 // File operations\r
1960 static int tftpfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode);\r
1961 static int tftpfs_fo_close(struct CYG_FILE_TAG *fp);\r
1962 static int tftpfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence);\r
1963 \r
1964 //==========================================================================\r
1965 // Filesystem table entries\r
1966 \r
1967 // -------------------------------------------------------------------------\r
1968 // Fstab entry.\r
1969 // This defines the entry in the filesystem table.\r
1970 // For simplicity we use _FILESYSTEM synchronization for all accesses since\r
1971 // we should never block in any filesystem operations.\r
1972 #if 1\r
1973 FSTAB_ENTRY( tftpfs_fste, "tftpfs", 0,\r
1974                 CYG_SYNCMODE_NONE,\r
1975                 tftpfs_mount,\r
1976                 tftpfs_umount,\r
1977                 tftpfs_open,\r
1978                 (cyg_fsop_unlink *)cyg_fileio_erofs,\r
1979                 (cyg_fsop_mkdir *)cyg_fileio_erofs,\r
1980                 (cyg_fsop_rmdir *)cyg_fileio_erofs,\r
1981                 (cyg_fsop_rename *)cyg_fileio_erofs,\r
1982                 (cyg_fsop_link *)cyg_fileio_erofs,\r
1983                 (cyg_fsop_opendir *)cyg_fileio_erofs,\r
1984                 (cyg_fsop_chdir *)cyg_fileio_erofs,\r
1985                 (cyg_fsop_stat *)cyg_fileio_erofs,\r
1986                 (cyg_fsop_getinfo *)cyg_fileio_erofs,\r
1987                 (cyg_fsop_setinfo *)cyg_fileio_erofs);\r
1988 #endif\r
1989 \r
1990 // -------------------------------------------------------------------------\r
1991 // mtab entry.\r
1992 // This defines a single ROMFS loaded into ROM at the configured address\r
1993 //\r
1994 // MTAB_ENTRY(  rom_mte,        // structure name\r
1995 //              "/rom",         // mount point\r
1996 //              "romfs",        // FIlesystem type\r
1997 //              "",             // hardware device\r
1998 //  (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS   // Address in ROM\r
1999 //           );\r
2000 \r
2001 \r
2002 // -------------------------------------------------------------------------\r
2003 // File operations.\r
2004 // This set of file operations are used for normal open files.\r
2005 \r
2006 static cyg_fileops tftpfs_fileops =\r
2007 {\r
2008         tftpfs_fo_read,\r
2009         tftpfs_fo_write,\r
2010         tftpfs_fo_lseek,\r
2011         (cyg_fileop_ioctl *)cyg_fileio_erofs,\r
2012     cyg_fileio_seltrue,\r
2013     tftpfs_fo_fsync,\r
2014     tftpfs_fo_close,\r
2015                 (cyg_fileop_fstat *) cyg_fileio_erofs,\r
2016                 (cyg_fileop_getinfo *) cyg_fileio_erofs,\r
2017         (cyg_fileop_setinfo *)cyg_fileio_erofs,\r
2018 };\r
2019 \r
2020 // -------------------------------------------------------------------------\r
2021 // tftpfs_mount()\r
2022 // Process a mount request. This mainly finds root for the\r
2023 // filesystem.\r
2024 \r
2025 static int tftpfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)\r
2026 {\r
2027         return ENOERR;\r
2028 }\r
2029 \r
2030 static int tftpfs_umount(cyg_mtab_entry *mte)\r
2031 {\r
2032         return ENOERR;\r
2033 }\r
2034 \r
2035 struct Tftp\r
2036 {\r
2037         int write;\r
2038         int readFile;\r
2039         cyg_uint8 *mem;\r
2040         int actual;\r
2041         char *server;\r
2042         char *file;\r
2043 };\r
2044 \r
2045 static void freeTftp(struct Tftp *t)\r
2046 {\r
2047         if (t == NULL)\r
2048                 return;\r
2049         if (t->mem)\r
2050                 free(t->mem);\r
2051         if (t->server)\r
2052                 free(t->server);\r
2053         if (t->file)\r
2054                 free(t->file);\r
2055         free(t);\r
2056 }\r
2057 \r
2058 static const int tftpMaxSize = 8192 * 1024;\r
2059 static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,\r
2060                 int mode, cyg_file *file)\r
2061 {\r
2062         struct Tftp *tftp;\r
2063         tftp = malloc(sizeof(struct Tftp));\r
2064         if (tftp == NULL)\r
2065                 return EMFILE;\r
2066         memset(tftp, 0, sizeof(struct Tftp));\r
2067 \r
2068         file->f_flag |= mode & CYG_FILE_MODE_MASK;\r
2069         file->f_type = CYG_FILE_TYPE_FILE;\r
2070         file->f_ops = &tftpfs_fileops;\r
2071         file->f_offset = 0;\r
2072         file->f_data = 0;\r
2073         file->f_xops = 0;\r
2074 \r
2075         tftp->mem = malloc(tftpMaxSize);\r
2076         if (tftp->mem == NULL)\r
2077         {\r
2078                 freeTftp(tftp);\r
2079                 return EMFILE;\r
2080         }\r
2081 \r
2082         char *server = strchr(name, '/');\r
2083         if (server == NULL)\r
2084         {\r
2085                 freeTftp(tftp);\r
2086                 return EMFILE;\r
2087         }\r
2088 \r
2089         tftp->server = malloc(server - name + 1);\r
2090         if (tftp->server == NULL)\r
2091         {\r
2092                 freeTftp(tftp);\r
2093                 return EMFILE;\r
2094         }\r
2095         strncpy(tftp->server, name, server - name);\r
2096         tftp->server[server - name] = 0;\r
2097 \r
2098         tftp->file = strdup(server + 1);\r
2099         if (tftp->file == NULL)\r
2100         {\r
2101                 freeTftp(tftp);\r
2102                 return EMFILE;\r
2103         }\r
2104 \r
2105         file->f_data = (CYG_ADDRWORD) tftp;\r
2106 \r
2107         return ENOERR;\r
2108 }\r
2109 \r
2110 static int fetchTftp(struct Tftp *tftp)\r
2111 {\r
2112         if (!tftp->readFile)\r
2113         {\r
2114                 int err;\r
2115             tftp->actual = tftp_client_get( tftp->file, tftp->server, 0, tftp->mem, tftpMaxSize,   TFTP_OCTET, &err);\r
2116 \r
2117                 if (tftp->actual < 0)\r
2118                 {\r
2119                         return EMFILE;\r
2120                 }\r
2121                 tftp->readFile = 1;\r
2122         }\r
2123         return ENOERR;\r
2124 }\r
2125 \r
2126 // -------------------------------------------------------------------------\r
2127 // tftpfs_fo_write()\r
2128 // Read data from file.\r
2129 \r
2130 static int\r
2131 tftpfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)\r
2132 {\r
2133         struct Tftp *tftp = (struct Tftp *) fp->f_data;\r
2134 \r
2135         if (fetchTftp(tftp) != ENOERR)\r
2136                 return EMFILE;\r
2137 \r
2138         int i;\r
2139         off_t pos = fp->f_offset;\r
2140         int resid = 0;\r
2141         for (i = 0; i < uio->uio_iovcnt; i++)\r
2142         {\r
2143                 cyg_iovec *iov = &uio->uio_iov[i];\r
2144                 char *buf = (char *) iov->iov_base;\r
2145                 off_t len = iov->iov_len;\r
2146 \r
2147                 if (len + pos > tftp->actual)\r
2148                 {\r
2149                         len = tftp->actual - pos;\r
2150                 }\r
2151                 resid += iov->iov_len - len;\r
2152 \r
2153                 memcpy(buf, tftp->mem + pos, len);\r
2154                 pos += len;\r
2155 \r
2156         }\r
2157         uio->uio_resid = resid;\r
2158         fp->f_offset = pos;\r
2159 \r
2160         return ENOERR;\r
2161 }\r
2162 \r
2163 \r
2164 static int\r
2165 tftpfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)\r
2166 {\r
2167         struct Tftp *tftp = (struct Tftp *) fp->f_data;\r
2168 \r
2169         int i;\r
2170         off_t pos = fp->f_offset;\r
2171         int resid = 0;\r
2172         for (i = 0; i < uio->uio_iovcnt; i++)\r
2173         {\r
2174                 cyg_iovec *iov = &uio->uio_iov[i];\r
2175                 char *buf = (char *) iov->iov_base;\r
2176                 off_t len = iov->iov_len;\r
2177 \r
2178                 if (len + pos > tftpMaxSize)\r
2179                 {\r
2180                         len = tftpMaxSize - pos;\r
2181                 }\r
2182                 resid += iov->iov_len - len;\r
2183 \r
2184                 memcpy(tftp->mem + pos, buf, len);\r
2185                 pos += len;\r
2186 \r
2187         }\r
2188         uio->uio_resid = resid;\r
2189         fp->f_offset = pos;\r
2190 \r
2191         tftp->write = 1;\r
2192 \r
2193         return ENOERR;\r
2194 }\r
2195 \r
2196 static int\r
2197 tftpfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)\r
2198 {\r
2199         int error = ENOERR;\r
2200         return error;\r
2201 }\r
2202 \r
2203 // -------------------------------------------------------------------------\r
2204 // romfs_fo_close()\r
2205 // Close a file. We just clear out the data pointer.\r
2206 \r
2207 static int tftpfs_fo_close(struct CYG_FILE_TAG *fp)\r
2208 {\r
2209         struct Tftp *tftp = (struct Tftp *) fp->f_data;\r
2210         int error = ENOERR;\r
2211 \r
2212         if (tftp->write)\r
2213         {\r
2214             tftp_client_put( tftp->file, tftp->server, 0, tftp->mem, fp->f_offset,   TFTP_OCTET, &error);\r
2215         }\r
2216 \r
2217         freeTftp(tftp);\r
2218         fp->f_data = 0;\r
2219         return error;\r
2220 }\r
2221 \r
2222 // -------------------------------------------------------------------------\r
2223 // romfs_fo_lseek()\r
2224 // Seek to a new file position.\r
2225 \r
2226 static int tftpfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)\r
2227 {\r
2228         struct Tftp *tftp = (struct Tftp *) fp->f_data;\r
2229         off_t pos = *apos;\r
2230 \r
2231         if (fetchTftp(tftp) != ENOERR)\r
2232                 return EMFILE;\r
2233 \r
2234         switch (whence)\r
2235         {\r
2236         case SEEK_SET:\r
2237                 // Pos is already where we want to be.\r
2238                 break;\r
2239 \r
2240         case SEEK_CUR:\r
2241                 // Add pos to current offset.\r
2242                 pos += fp->f_offset;\r
2243                 break;\r
2244 \r
2245         case SEEK_END:\r
2246                 // Add pos to file size.\r
2247                 pos += tftp->actual;\r
2248                 break;\r
2249 \r
2250         default:\r
2251                 return EINVAL;\r
2252         }\r
2253 \r
2254         // Check that pos is still within current file size, or at the\r
2255         // very end.\r
2256         if (pos < 0 || pos > tftp->actual)\r
2257                 return EINVAL;\r
2258 \r
2259         // All OK, set fp offset and return new position.\r
2260         *apos = fp->f_offset = pos;\r
2261 \r
2262         return ENOERR;\r
2263 }\r
2264 \r
2265 void usleep(int us)\r
2266 {\r
2267         if (us > 10000)\r
2268                 cyg_thread_delay(us / 10000 + 1);\r
2269         else\r
2270                 HAL_DELAY_US(us);\r
2271 }\r
2272 \r
2273 // Chunked version.\r
2274 cyg_int32\r
2275 show_log_entry(CYG_HTTPD_STATE *phttpstate)\r
2276 {\r
2277         cyg_httpd_start_chunked("text");\r
2278         if (logCount >= logSize)\r
2279         {\r
2280         cyg_httpd_write_chunked(logBuffer+logCount%logSize, logSize-logCount%logSize);\r
2281         }\r
2282         cyg_httpd_write_chunked(logBuffer, writePtr);\r
2283         cyg_httpd_end_chunked();\r
2284         return -1;\r
2285 }\r
2286 \r
2287 CYG_HTTPD_HANDLER_TABLE_ENTRY(show_log, "/ram/log", show_log_entry);\r
2288 \r
2289 // Filesystem operations\r
2290 static int logfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte);\r
2291 static int logfs_umount(cyg_mtab_entry *mte);\r
2292 static int logfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,\r
2293                 int mode, cyg_file *fte);\r
2294 static int\r
2295 logfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);\r
2296 \r
2297 // File operations\r
2298 static int logfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode);\r
2299 static int logfs_fo_close(struct CYG_FILE_TAG *fp);\r
2300 \r
2301 //==========================================================================\r
2302 // Filesystem table entries\r
2303 \r
2304 // -------------------------------------------------------------------------\r
2305 // Fstab entry.\r
2306 // This defines the entry in the filesystem table.\r
2307 // For simplicity we use _FILESYSTEM synchronization for all accesses since\r
2308 // we should never block in any filesystem operations.\r
2309 FSTAB_ENTRY( logfs_fste, "logfs", 0,\r
2310                 CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,\r
2311                 logfs_mount,\r
2312                 logfs_umount,\r
2313                 logfs_open,\r
2314                 (cyg_fsop_unlink *)cyg_fileio_erofs,\r
2315                 (cyg_fsop_mkdir *)cyg_fileio_erofs,\r
2316                 (cyg_fsop_rmdir *)cyg_fileio_erofs,\r
2317                 (cyg_fsop_rename *)cyg_fileio_erofs,\r
2318                 (cyg_fsop_link *)cyg_fileio_erofs,\r
2319                 (cyg_fsop_opendir *)cyg_fileio_erofs,\r
2320                 (cyg_fsop_chdir *)cyg_fileio_erofs,\r
2321                 (cyg_fsop_stat *)cyg_fileio_erofs,\r
2322                 (cyg_fsop_getinfo *)cyg_fileio_erofs,\r
2323                 (cyg_fsop_setinfo *)cyg_fileio_erofs);\r
2324 \r
2325 // -------------------------------------------------------------------------\r
2326 // File operations.\r
2327 // This set of file operations are used for normal open files.\r
2328 \r
2329 static cyg_fileops logfs_fileops =\r
2330 {\r
2331         (cyg_fileop_read *)cyg_fileio_erofs,\r
2332     (cyg_fileop_write *)logfs_fo_write,\r
2333                 (cyg_fileop_lseek *) cyg_fileio_erofs,\r
2334         (cyg_fileop_ioctl *)cyg_fileio_erofs,\r
2335     cyg_fileio_seltrue,\r
2336     logfs_fo_fsync,\r
2337     logfs_fo_close,\r
2338         (cyg_fileop_fstat *)cyg_fileio_erofs,\r
2339                 (cyg_fileop_getinfo *) cyg_fileio_erofs,\r
2340         (cyg_fileop_setinfo *)cyg_fileio_erofs,\r
2341 };\r
2342 \r
2343 // -------------------------------------------------------------------------\r
2344 // logfs_mount()\r
2345 // Process a mount request. This mainly finds root for the\r
2346 // filesystem.\r
2347 \r
2348 static int logfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)\r
2349 {\r
2350         return ENOERR;\r
2351 }\r
2352 \r
2353 static int logfs_umount(cyg_mtab_entry *mte)\r
2354 {\r
2355         return ENOERR;\r
2356 }\r
2357 \r
2358 static int logfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,\r
2359                 int mode, cyg_file *file)\r
2360 {\r
2361         file->f_flag |= mode & CYG_FILE_MODE_MASK;\r
2362         file->f_type = CYG_FILE_TYPE_FILE;\r
2363         file->f_ops = &logfs_fileops;\r
2364         file->f_offset = 0;\r
2365         file->f_data = 0;\r
2366         file->f_xops = 0;\r
2367         return ENOERR;\r
2368 }\r
2369 \r
2370 // -------------------------------------------------------------------------\r
2371 // logfs_fo_write()\r
2372 // Write data to file.\r
2373 \r
2374 static int\r
2375 logfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)\r
2376 {\r
2377         int i;\r
2378         for (i = 0; i < uio->uio_iovcnt; i++)\r
2379         {\r
2380                 cyg_iovec *iov = &uio->uio_iov[i];\r
2381                 char *buf = (char *) iov->iov_base;\r
2382                 off_t len = iov->iov_len;\r
2383 \r
2384                 diag_write(buf, len);\r
2385         }\r
2386         uio->uio_resid = 0;\r
2387 \r
2388         return ENOERR;\r
2389 }\r
2390 static int\r
2391 logfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)\r
2392 {\r
2393         return ENOERR;\r
2394 }\r
2395 \r
2396 // -------------------------------------------------------------------------\r
2397 // romfs_fo_close()\r
2398 // Close a file. We just clear out the data pointer.\r
2399 \r
2400 static int logfs_fo_close(struct CYG_FILE_TAG *fp)\r
2401 {\r
2402         return ENOERR;\r
2403 }\r