e1e12b75f1733e66d5bf18260b508671b8328787
[my-code/arm.git] / betty / lpcload.c
1 /*
2  * lpcload.c - load firmware into ram of lpc2220 via uart0
3  *
4  * author: hackbard@hackdaworld.org, rolf.anders@physik.uni-augsburg.de
5  *
6  * build: make
7  * usage: sudo ./lpcload -d /dev/ttyS0 -f firmware.hex -D0 fw0.bin [-v]
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <termios.h>
18
19 #define VERBOSE                 (1<<0)
20 #define FIRMWARE                (1<<1)
21 #define BANK0                   (1<<2)
22 #define BANK2                   (1<<3)
23 #define BL                      (1<<4)
24 #define FLASHFW                 (1<<5)
25 #define BINARY                  (1<<6)
26
27 #define BANK0_ADDR              0x80000000
28 #define BANK2_ADDR              0x82000000
29 #define BANK_SIZE               0x00100000
30 #define BL_ADDR                 0x7fffe000
31 #define BL_SIZE                 0x00002000
32
33 #define CMD_READ                'R'             // stay compatible to fwflash!
34 #define CMD_WRITE               'W'
35 #define CMD_CHIP_ERASE          'E'
36
37 #define TXRX_TYPE_SYNC          0x00
38 #define TXRX_TYPE_CKSM          0x00
39 #define TXRX_TYPE_BAUD          0x01
40 #define TXRX_TYPE_CMD           0x02
41 #define TXRX_TYPE_DATA          0x03
42 #define TXRX_TYPE_GO            0x04
43
44 #define CMD_SUCCESS             "0\r\n"
45 #define INVALID_COMMAND         "1\r\n"
46 #define SRC_ADDR_ERROR          "2\r\n"
47 #define DST_ADDR_ERROR          "3\r\n"
48 #define SRC_ADDR_NOT_MAPPED     "4\r\n"
49 #define DST_ADDR_NOT_MAPPED     "5\r\n"
50 #define COUNT_ERROR             "6\r\n"
51 #define COMPARE_ERROR           "10\r\n"
52 #define BUSY                    "11\r\n"
53 #define PARAM_ERROR             "12\r\n"
54 #define ADDR_ERROR              "13\r\n"
55 #define ADDR_NOT_MAPPED         "14\r\n"
56 #define CMD_LOCKED              "15\r\n"
57 #define INVALID_CODE            "16\r\n"
58 #define INVALID_BAUD_RATE       "17\r\n"
59 #define INVALID_STOP_BIT        "18\r\n"
60
61 #define RAM                     0x01
62 #define FLASH                   0x02
63
64 #define CRYSTFREQ               "10000"
65 #define RAMOFFSET               0x40000200
66
67 #define BUFSIZE                 128
68
69 typedef unsigned char u8;
70 typedef unsigned short u16;
71 typedef unsigned int u32;
72
73 typedef struct s_lpc {
74         int sfd;                /* serial fd */
75         char sdev[128];         /* seriel device */
76         int fwfd;               /* fimrware fd */
77         char fwfile[128];       /* firmware file */
78         u32 info;               /* info/mode */
79         char freq[8];           /* frequency */
80         char bank0[127];        /* flash dump bank0 */
81         int b0fd;               /* dumpfile fd bank0 */
82         char bank2[127];        /* flash dump bank2 */
83         int b2fd;               /* dumpfile fd bank0 */
84         char bl[127];           /* flash dump bootloader */
85         int blfd;               /* dumpfile fd bootloader */
86         char ffwfile[127];      /* file with firmware to be flashed */
87         int ffwfd;              /* fd of the above */
88         u32 roff;               /* ram offset of uc */
89         u32 jaddr;              /* addr for the jump */
90 } t_lpc;
91
92 void usage(void) {
93
94         printf("possible argv:\n");
95         printf("  -d  <serial device>\n");
96         printf("  -f  <firmware>\n");
97         printf("  -c  <crystal freq>\n");
98         printf("  -Dx <filename>\n");
99         printf("      x=0: bank0, x=2: bank2, x=b: bootloader\n");
100         printf("  -w <firmware which goes to flash>\n");
101         printf("  -b (if firmware for flash is a binary)\n");
102         printf("  -v\n");
103
104 }
105
106 int open_serial_device(t_lpc *lpc) {
107
108         struct termios term;
109
110         //memset(&term,0,sizeof(struct termios));
111
112         /* open serial device */
113
114         lpc->sfd=open(lpc->sdev,O_RDWR);
115         if(lpc->sfd<0) {
116                 perror("tts open");
117                 return lpc->sfd;
118         }
119
120         /* configure the serial device */
121
122         tcgetattr(lpc->sfd,&term);
123
124         // input/output baudrate
125
126         cfsetispeed(&term,B38400);
127         cfsetospeed(&term,B38400);
128
129         // control options -> 8n1
130
131         term.c_cflag&=~PARENB;  // no parity
132         term.c_cflag&=~CSTOPB;  // only 1 stop bit
133         term.c_cflag&=~CSIZE;   // no bit mask for data bits
134         term.c_cflag|=CS8;      // 8 data bits
135
136         // line options -> raw input
137         
138         term.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
139
140         // input options -> enable flow control
141         
142         term.c_iflag&=~(INLCR|ICRNL|IXANY);
143         term.c_iflag|=(IXON|IXOFF);
144         
145         // output options
146
147         term.c_oflag=0;
148
149         // more control options -> timeout / flow control
150         
151         term.c_cc[VMIN]=0;
152         term.c_cc[VTIME]=20;    // 2 seconds timeout
153         //term.c_cc[VSTART]=0x11;
154         //term.c_cc[VSTOP]=0x13;
155
156         tcsetattr(lpc->sfd,TCSANOW,&term);
157
158         return lpc->sfd;
159 }
160
161 int reconfig_serial_device(t_lpc *lpc) {
162
163         struct termios term;
164         int ret;
165
166         /* reconfigure the serial device for our lousy loader tool */
167
168         tcgetattr(lpc->sfd,&term);
169
170         // disable flow control
171         
172         term.c_iflag&=~(IXON|IXOFF|IXANY|INLCR|ICRNL);
173
174         // change baudrate
175
176         cfsetispeed(&term,B115200);
177         cfsetospeed(&term,B115200);
178
179         // timeouts
180         
181         term.c_cc[VMIN]=0;
182         term.c_cc[VTIME]=100;   // 10 seconds timeout
183
184         ret=tcsetattr(lpc->sfd,TCSANOW,&term);
185
186         return ret;
187 }
188
189 int open_firmware(t_lpc *lpc) {
190
191         /* open firmware file */
192
193         lpc->fwfd=open(lpc->fwfile,O_RDONLY);
194
195         if(lpc->fwfd<0) {
196                 perror("fw open");
197                 return lpc->fwfd;
198         }
199
200         if(lpc->info&FLASHFW) {
201                 lpc->ffwfd=open(lpc->ffwfile,O_RDONLY);
202                 if(lpc->ffwfd<0) {
203                         perror("ffw open");
204                         return lpc->ffwfd;
205                 }
206         }
207
208         return lpc->fwfd;
209 }
210
211 int open_dumpfiles(t_lpc *lpc) {
212
213         /* open dumpfiles */
214
215         if(lpc->info&BANK0) {
216                 lpc->b0fd=open(lpc->bank0,O_WRONLY|O_CREAT);
217                 if(lpc->b0fd<0) {
218                         perror("bank0 dump file open");
219                         return lpc->b0fd;
220                 }
221         }
222
223         if(lpc->info&BANK2) {
224                 lpc->b2fd=open(lpc->bank2,O_WRONLY|O_CREAT);
225                 if(lpc->b2fd<0) {
226                         perror("bank2 dump file open");
227                         return lpc->b2fd;
228                 }
229         }
230
231         if(lpc->info&BL) {
232                 lpc->blfd=open(lpc->bl,O_WRONLY|O_CREAT);
233                 if(lpc->blfd<0) {
234                         perror("bootloader dump file open");
235                         return lpc->blfd;
236                 }
237         }
238
239         return 0;
240
241 }
242 int txrx(t_lpc *lpc,char *buf,int len,u8 type) {
243
244         int ret,cnt;
245         int i;
246
247         /* write */
248
249         if(lpc->info&VERBOSE)
250                 printf("  >> ");
251         cnt=0;
252         while(len) {
253                 ret=write(lpc->sfd,buf+cnt,len);
254                 if(ret<0) {
255                         perror("txrx write");
256                         return ret;
257                 }
258                 if(lpc->info&VERBOSE)
259                         for(i=0;i<ret;i++)
260                                 printf("%c",
261                                        ((buf[cnt+i]>0x19)&(buf[cnt+i]<0x7f))?
262                                        buf[cnt+i]:'.');
263                 len-=ret;
264                 cnt+=ret;
265         }
266         if(lpc->info&VERBOSE) {
267                 printf(" | ");
268                 for(i=0;i<cnt;i++)
269                         printf("%02x ",buf[i]);
270                 printf("| (%d)\n",cnt);
271         }
272
273
274
275         /* cut the echo if not of type auto baud */
276
277         if(type!=TXRX_TYPE_BAUD) {
278                 while(cnt) {
279                         ret=read(lpc->sfd,buf,cnt);
280                         if(ret<0) {
281                                 perror("txrx echo cut");
282                                 return ret;
283                         }
284                         cnt-=ret;
285                 }
286         }
287
288         /* return if type is go */
289
290         if(type==TXRX_TYPE_GO)
291                 return cnt;
292
293         /* return here if type is data */
294
295         if(type==TXRX_TYPE_DATA)
296                 return cnt;
297
298         /* read */
299
300         ret=read(lpc->sfd,buf,1);
301         if(ret<0) {
302                 perror("txrx read (first byte)");
303                 return ret;
304         }
305                 
306         switch(buf[0]) {
307                 case 'S':
308                         cnt=13;
309                         break;
310                 case 'O':
311                         cnt=3;
312                         break;
313                 case 'R':
314                         cnt=7;
315                         break;
316                 case '0':
317                         cnt=2;
318                         break;
319                 default:
320                         printf("txrx read: bad return byte '%02x'\n",buf[0]);
321                         break;
322         }
323
324         ret=1;
325         i=cnt;
326         while(i) {
327                 ret=read(lpc->sfd,buf+1+cnt-i,i);
328                 if(ret<0) {
329                         perror("txrx read (next bytes)");
330                         return ret;
331                 }
332                 i-=ret;
333         }
334         if(lpc->info&VERBOSE) {
335                 printf("  << ");
336                 for(i=0;i<cnt+1;i++)
337                         printf("%c",((buf[i]>0x19)&(buf[i]<0x7f))?
338                                     buf[i]:'.');
339                 printf(" | ");
340                 for(i=0;i<cnt+1;i++)
341                         printf("%02x ",buf[i]);
342                 printf("| (%d)\n",cnt+1);
343         }
344         buf[cnt+1]='\0';
345
346         /* check/strip return code if type is cmd */
347
348         if(type==TXRX_TYPE_CMD) {
349                 ret=strlen(CMD_SUCCESS);
350                 if(!strncmp(buf,CMD_SUCCESS,ret)) {
351                         for(i=ret;i<cnt;i++)
352                                 buf[i-ret]=buf[i];
353                         buf[cnt]='\0';
354                 }
355                 else {
356                         printf("txrx bad return code!\n");
357                         return -1;
358                 }
359         }
360
361         return cnt;
362 }
363
364 int bl_init(t_lpc *lpc) {
365
366         char buf[BUFSIZE];
367         int len;
368
369         /* auto baud sequence */
370         buf[0]='?';
371         txrx(lpc,buf,1,TXRX_TYPE_BAUD);
372         if(strncmp(buf,"Synchronized\r\n",14)) {
373                 printf("auto baud detection failed\n");
374                 return -1;
375         }
376
377         /* tell bl that we are synchronized (it's allready in buf) */
378         txrx(lpc,buf,14,TXRX_TYPE_SYNC);
379         if(strncmp(buf,"OK\r\n",4)) {
380                 printf("sync failed\n");
381                 return -1;
382         }
383
384         /* tell bl the crystal frequency */
385         len=strlen(lpc->freq)+2;
386         strncpy(buf,lpc->freq,BUFSIZE);
387         buf[len-2]='\r';
388         buf[len-1]='\n';
389         txrx(lpc,buf,len,TXRX_TYPE_SYNC);
390         if(strncmp(buf,"OK\r\n",4)) {
391                 printf("freq set failed\n");
392                 return -1;
393         }
394
395         return 0;
396 }
397
398 int unlock_go(t_lpc *lpc) {
399
400         char buf[BUFSIZE];
401         int ret;
402
403         memcpy(buf,"U 23130\r\n",9);
404         ret=txrx(lpc,buf,9,TXRX_TYPE_CMD);
405
406         return ret;
407 }
408
409 int go(t_lpc *lpc) {
410
411         char buf[BUFSIZE];
412         int ret,len;
413
414         snprintf(buf,BUFSIZE,"G %d A\r\n",lpc->jaddr);
415         len=strlen(buf);
416         ret=txrx(lpc,buf,len,TXRX_TYPE_GO);
417
418         return ret;
419 }
420
421 int uuencode(u8 *in,u8 *out,int len) {
422
423         out[0]=0x20+len;
424         out[1]=0x20+((in[0]>>2)&0x3f);
425         out[2]=0x20+(((in[0]<<4)|(in[1]>>4))&0x3f);
426         out[3]=0x20+(((in[1]<<2)|(in[2]>>6))&0x3f);
427         out[4]=0x20+(in[2]&0x3f);
428
429         return 0;
430 }
431
432 int write_to_ram(t_lpc *lpc,char *buf,u32 addr,int len) {
433
434         int lcount;
435         u32 checksum;
436         char txrxbuf[BUFSIZE];
437         int count,bcnt;
438         int nlen,slen;
439         int i;
440
441         /* check length */
442         if(len%4) {
443                 printf("ram write: not a multiple of 4\n");
444                 return -1;
445         }
446
447         /* make it a multiple of 3 (reason: uuencode) */
448         nlen=(!(len%3))?len:((len/3+1)*3);
449         if(nlen>BUFSIZE) {
450                 printf("ram write: too much data\n");
451                 return -1;
452         }
453         for(i=len;i<nlen;i++) buf[i]=0;
454
455         /* prepare addr */
456         addr+=lpc->roff;
457
458         /* prepare write command */
459         if(lpc->info&VERBOSE)
460                 printf("writing 0x%02x bytes to 0x%08x\n",len,addr);
461         snprintf(txrxbuf,BUFSIZE,"W %d %d\r\n",addr,len);
462         slen=strlen(txrxbuf);
463
464         /* send command and check return code */
465         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CMD);
466
467         /* send data */
468         lcount=0;
469         bcnt=0;
470         count=0;
471         checksum=0;
472         while(bcnt<nlen) {
473
474                 /* uuencode / prepare data bytes */
475                 uuencode((u8 *)(buf+bcnt),(u8 *)(txrxbuf),
476                          (bcnt==nlen-3)?(len%3?len%3:3):3);
477                 txrxbuf[5]='\r';
478                 txrxbuf[6]='\n';
479
480                 /* checksum */
481                 checksum+=((u8)buf[bcnt]+(u8)buf[bcnt+1]+(u8)buf[bcnt+2]);
482
483                 /* send a data line */
484                 txrx(lpc,txrxbuf,7,TXRX_TYPE_DATA);
485
486                 /* increase counters */
487                 lcount+=1;
488                 bcnt+=3;
489                 count+=3;
490
491                 /* checksum */
492                 if((!(lcount%20))|(bcnt==nlen)) {
493                         /* send backtick */
494                         memcpy(txrxbuf,"`\r\n",3);
495                         //txrx(lpc,txrxbuf,3,TXRX_TYPE_DATA);
496                         /* send checksum */
497                         snprintf(txrxbuf,BUFSIZE,"%d\r\n",checksum);
498                         slen=strlen(txrxbuf);
499                         txrx(lpc,txrxbuf,slen,TXRX_TYPE_CKSM);
500                         if(!strncmp(txrxbuf,"RESE",4)) {
501                                 read(lpc->sfd,txrxbuf+4,4);
502                                 printf("ram write: resending ...\n");
503                                 bcnt-=count;
504                         }
505                         if(strncmp(txrxbuf,"OK\r\n",4)) {
506                                 printf("ram write: bad response\n");
507                                 return -1;
508                         }
509                         /* reset checksum & counter */
510                         checksum=0;
511                         count=0;
512                 }
513
514         }
515
516         return 0;
517 }
518
519 int send_cmd(int sfd,u32 addr,u32 len,u8 cmd) {
520
521         int ret,i,cnt,size;
522         int as,ls;
523         u8 send[9];
524
525         switch(cmd) {
526                 case CMD_READ:
527                 case CMD_WRITE:
528                         as=4;
529                         ls=4;
530                         break;
531                 case CMD_CHIP_ERASE:
532                         as=0;
533                         ls=1;
534                         break;
535                 default:
536                         printf("send cmd: cmd '%02x' not supported\n",cmd);
537                         return -1;
538         }
539
540         size=1+as+ls;
541         send[0]=cmd;
542
543         for(i=0;i<as;i++)
544                 send[1+i]=(addr>>((as-1-i)*8))&0xff;
545         for(i=0;i<ls;i++)
546                 send[1+i+as]=(len>>((ls-1-i)*8))&0xff;
547
548         cnt=0;
549         while(size) {
550                 ret=write(sfd,send+cnt,size);
551                 if(ret<0) {
552                         perror("dump file: send cmd ");
553                         return ret;
554                 }
555                 size-=ret;
556                 cnt+=ret;
557         }
558
559         return 0;
560 }
561
562 int write_to_flash(t_lpc *lpc,u8 *buf,u32 addr,int len) {
563
564         int cnt,ret;
565         u8 cksml,cksmr;
566         u8 check;
567         int i;
568
569         /* prepare addr */
570         addr+=lpc->roff;
571
572         /* send cmd */
573         send_cmd(lpc->sfd,addr,len,CMD_WRITE);
574
575         /* transfer data */
576         cnt=0;
577         cksml=0;
578         while(len) {
579                 for(i=0;i<2;i++) {
580                         while(1) {
581                                 ret=write(lpc->sfd,buf+cnt+i,1);
582                                 if(ret<0) {
583                                         perror("transmit flash content (w)");
584                                         return ret;
585                                 }
586                                 if(ret==1)
587                                         break;
588                         }
589                         while(1) {
590                                 ret=read(lpc->sfd,&check,1);
591                                 if(ret<0) {
592                                         perror("transmit flash content (r)");
593                                         return ret;
594                                 }
595                                 if(ret==1)
596                                         break;
597                         }
598                         if(buf[cnt+i]!=check)
599                                 printf("FATAL: write to flash (transfer)\n");
600                 }
601                 cksml+=buf[cnt];
602                 cksml+=buf[cnt+1];
603                 cnt+=2;
604                 len-=2;
605         }
606
607
608         /*
609         cnt=0;
610         cksml=0;
611         while(len) {
612                 ret=write(lpc->sfd,buf+cnt,len);
613                 if(ret<0) {
614                         perror("transmit flash content (w)");
615                         return ret;
616                 }
617                 for(i=cnt;i<cnt+ret;i++)
618                         cksml+=buf[i];
619                 len-=ret;
620                 cnt+=ret;
621         }
622         */
623
624         /* check ack */
625         while(1) {
626                 ret=read(lpc->sfd,&cksmr,1);
627                 if(ret<0) {
628                         perror("write to flash: read cksm");
629                         return ret;
630                 }
631                 if(ret==1) break;
632         }
633         if(cksml!=cksmr) {
634                 printf("FATAL: wrong checksum or failure in flash write!\n");
635                 if(cksml+1==cksmr)
636                         printf(" -> most probably due to flash write!\n");
637                 else
638                         printf(" -> most probably failure in transfer!\n");
639                 printf(" addr:0x%08x l:%02x r:%02x\n",addr,cksml,cksmr);
640         }
641
642         return 0;
643 }
644
645 int firmware_to_mem(t_lpc *lpc,u8 memtype) {
646
647         char buf[BUFSIZE];
648         u32 addr,len,type;
649         int ret,temp;
650         int fd;
651
652         /* prepare for memory type */
653         if(memtype==RAM)
654                 fd=lpc->fwfd;
655         else if(memtype==FLASH)
656                 fd=lpc->ffwfd;
657         else
658                 return -1;
659
660         /* another evil hack to support binary format */
661         if((lpc->info&BINARY)&&(memtype==FLASH)) {
662                 addr=0;
663                 ret=1;
664                 while(ret) {
665                         ret=read(fd,buf,16);
666                         if(ret!=16) {
667                                 printf("D'OH ...\n");
668                                 return -1;
669                         }
670                         buf[16]='s'; // skip
671                         for(temp=0;temp<16;temp++)
672                                 if((u8)buf[temp]!=0xff)
673                                         buf[16]='w'; // write
674                         printf("addr:%08x\r",addr+lpc->roff);
675                         fflush(stdout);
676                         if(buf[16]=='w') 
677                                 write_to_flash(lpc,(u8 *)buf,addr,16);
678                         addr+=16;
679                 }
680                 return 0;
681         }
682
683         /* read a line */
684         ret=1;
685         while(ret) {
686                 /* sync line */
687                 ret=read(fd,buf,1);
688                 switch(buf[0]) {
689                         case '\r':
690                                 continue;
691                         case '\n':
692                                 continue;
693                         case ':':
694                                 /* start code */
695                                 break;
696                         default:
697                                 printf("fw to mem: no ihex format\n");
698                                 return -1;
699                 }
700                 /* read len */
701                 ret=read(fd,buf,2);
702                 sscanf(buf,"%02x",&len);
703                 /* read addr */
704                 ret=read(fd,buf,4);
705                 sscanf(buf,"%04x",&addr);
706                 /* read type */
707                 ret=read(fd,buf,2);
708                 sscanf(buf,"%02x",&type);
709                 /* successfull return if type is end of file */
710                 if(type==0x01)
711                         return 0;
712                 /* read data (and cksum) */
713                 ret=read(fd,buf,2*(len+1));
714                 if(ret!=(2*(len+1))) {
715                         printf("fw to mem: data missing\n");
716                                 return -1;
717                 }
718                 for(ret=0;ret<len;ret++) {
719                         sscanf(buf+2*ret,"%02x",&temp);
720                         buf[ret]=temp;
721                 }
722                 /* act according to type */
723                 switch(type) {
724                         //case 0x03:
725                         //      /* get cs and ip */
726                         //      break;
727                         case 0x00:
728                                 if(len%4) {
729                                         printf("fw to mem: invalid len\n");
730                                         return -1;
731                                 }
732                                 if(memtype==RAM)
733                                         write_to_ram(lpc,buf,addr,len);
734                                 else
735                                         write_to_flash(lpc,(u8 *)buf,addr,len);
736                                 break;
737                         case 0x04:
738                                 lpc->roff=((buf[0]<<24)|(buf[1]<<16));
739                                 break;
740                         case 0x05:
741                                 lpc->jaddr=((buf[0]<<24)|(buf[1]<<16));
742                                 lpc->jaddr|=((buf[2]<<8)|buf[3]);
743                                 break;
744                         default:
745                                 printf("fw to mem: unknown type %02x\n",type);
746                                 return -1;
747                 }
748         }
749
750         return 0;
751 }
752
753 int lpc_txbuf_flush(t_lpc *lpc) {
754
755         int i,ret;
756         u8 buf[16];
757
758         ret=1;
759         printf("flushing lpc tx buffer: ");
760         while(ret) {
761                 ret=read(lpc->sfd,buf,16);
762                 for(i=0;i<ret;i++)
763                         printf("%02x ",buf[i]);
764         }
765         printf("\n");
766
767         return 0;
768 }
769
770 int dump_files(int sfd,int dfd,u32 addr,u32 len) {
771
772         int ret;
773         int size;
774         int cnt;
775         u8 buf[16];
776
777         printf("dumping content (addr=0x%08x, len=0x%08x) ...\n",addr,len);
778
779         /* send the cmd */
780         send_cmd(sfd,addr,len,CMD_READ);
781
782         /* receive data and dump it to file */
783         ret=1;
784         cnt=0;
785         printf("  receiving data ...\n");
786         while(ret) {
787                 ret=read(sfd,buf,16);
788                 if(ret<0) {
789                         perror("dump file: read data");
790                         return ret;
791                 }
792                 size=ret;
793                 cnt=0;
794                 while(size) {
795                         ret=write(dfd,buf+cnt,size-cnt);
796                         if(ret<0) {
797                                 perror("dump file: write data");
798                                 return ret;
799                         }
800                         cnt+=ret;
801                         size-=ret;
802                 }
803         }
804
805         return 0;
806 }
807
808 int main(int argc,char **argv) {
809
810         t_lpc lpc;
811         int i;
812         int ret;
813
814         /*
815          * initial ... 
816          */
817
818         memset(&lpc,0,sizeof(t_lpc));
819         strncpy(lpc.freq,CRYSTFREQ,7);
820         lpc.roff=RAMOFFSET;
821         lpc.jaddr=RAMOFFSET;
822
823         /* parse argv */
824
825         for(i=1;i<argc;i++) {
826
827                 if(argv[i][0]!='-') {
828                         usage();
829                         return -1;
830                 }
831
832                 switch(argv[i][1]) {
833                         case 'd':
834                                 strncpy(lpc.sdev,argv[++i],127);
835                                 break;
836                         case 'f':
837                                 strncpy(lpc.fwfile,argv[++i],127);
838                                 lpc.info|=FIRMWARE;
839                                 break;
840                         case 'v':
841                                 lpc.info|=VERBOSE;
842                                 break;
843                         case 'c':
844                                 strncpy(lpc.freq,argv[++i],7);
845                                 break;
846                         case 'D':
847                                 if(argv[i][2]=='0') {
848                                         lpc.info|=BANK0;
849                                         strncpy(lpc.bank0,argv[++i],127);
850                                         break;
851                                 }
852                                 else if(argv[i][2]=='2') {
853                                         lpc.info|=BANK2;
854                                         strncpy(lpc.bank2,argv[++i],127);
855                                         break;
856                                 }
857                                 else if(argv[i][2]=='b') {
858                                         lpc.info|=BL;
859                                         strncpy(lpc.bl,argv[++i],127);
860                                         break;
861                                 }
862                                 else {
863                                         usage();
864                                         return -1;
865                                 }
866                         case 'w':
867                                 strncpy(lpc.ffwfile,argv[++i],127);
868                                 lpc.info|=FLASHFW;
869                                 break;
870                         case 'b':
871                                 lpc.info|=BINARY;
872                                 break;
873                         default:
874                                 usage();
875                                 return -1;
876                 }
877
878         }
879
880         /* open serial port */
881         if(open_serial_device(&lpc)<0)
882                 goto end;
883
884         /* boot loader init */
885         printf("boot loader init ...\n");
886         if(bl_init(&lpc)<0)
887                 return -1;
888
889         /* quit if there is no hex file to process */
890         if(!(lpc.info&FIRMWARE)) {
891                 printf("no firmware -> aborting\n");
892                 goto end;
893         }
894
895         /* open firmware file */
896         if(open_firmware(&lpc)<0)
897                 goto end;
898
899         /* open dump files */
900         if(open_dumpfiles(&lpc)<0)
901                 goto end;
902
903         /* parse intel hex file and write to ram */
904         printf("write firmware to ram ...\n");
905         firmware_to_mem(&lpc,RAM);
906
907         /* unlock go cmd */
908         printf("unlock go command ...\n");
909         unlock_go(&lpc);
910
911         /* go! */
912         printf("go ...\n");
913         ret=go(&lpc);
914
915         /* flush the lpc2220 tx buf */
916         lpc_txbuf_flush(&lpc);
917
918         /* reconfigure the serial port */
919         if(reconfig_serial_device(&lpc)<0)
920                 goto end;
921
922         /* download flash/bootloader content */
923         if(lpc.info&BANK0)
924                 dump_files(lpc.sfd,lpc.b0fd,BANK0_ADDR,BANK_SIZE);
925         if(lpc.info&BANK2)
926                 dump_files(lpc.sfd,lpc.b2fd,BANK2_ADDR,BANK_SIZE);
927         if(lpc.info&BL)
928                 dump_files(lpc.sfd,lpc.blfd,BL_ADDR,BL_SIZE);
929
930         /* write a firmware to the lpc flash */
931         if(lpc.info&FLASHFW) {
932                 printf("writing firmware to flash ...\n");
933                 send_cmd(lpc.sfd,0,'0',CMD_CHIP_ERASE);
934                 lpc.roff=BANK0_ADDR;
935                 firmware_to_mem(&lpc,FLASH);
936         }
937
938 end:
939         if(lpc.sfd)
940                 close(lpc.sfd);
941         if(lpc.fwfd)
942                 close(lpc.fwfd);
943         if(lpc.b0fd)
944                 close(lpc.b0fd);
945         if(lpc.b2fd)
946                 close(lpc.b2fd);
947         if(lpc.blfd)
948                 close(lpc.blfd);
949         if(lpc.ffwfd)
950                 close(lpc.ffwfd);
951
952         return 0;
953 }
954