]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/dgap/downld.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / dgap / downld.c
1 /*
2  * Copyright 2003 Digi International (www.digi.com)
3  *      Scott H Kilau <Scott_Kilau at digi dot com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13  * PURPOSE.  See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
20  */
21
22 /*
23 ** downld.c
24 **
25 **  This is the daemon that sends the fep, bios, and concentrator images
26 **  from user space to the driver.
27 ** BUGS: 
28 **  If the file changes in the middle of the download, you probably
29 **     will get what you deserve.
30 **
31 */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/errno.h>
39
40 #include "dgap_types.h"
41 #include "digi.h"
42 #include "dgap_fep5.h"
43
44 #include "dgap_downld.h"
45
46 #include <string.h>
47 #include <malloc.h>
48 #include <stddef.h>
49 #include <unistd.h>
50
51 char            *pgm;
52 void            myperror();
53
54 /*
55 **  This structure is used to keep track of the different images available
56 **  to give to the driver.  It is arranged so that the things that are
57 **  constants or that have defaults are first inthe strucutre to simplify
58 **  the table of initializers.
59 */
60 struct image_info {
61         short   type;           /* bios, fep, conc */
62         short   family;         /* boards this applies to */
63         short   subtype;        /* subtype */
64         int     len;            /* size of image */
65         char    *image;         /* ioctl struct + image */
66         char    *name;
67         char    *fname;         /* filename of binary (i.e. "asfep.bin") */
68         char    *pathname;      /* pathname to this binary ("/etc/dgap/xrfep.bin"); */
69         time_t  mtime;          /* Last modification time */
70 };
71
72 #define IBIOS   0
73 #define IFEP    1
74 #define ICONC   2
75 #define ICONFIG 3
76 #define IBAD    4
77
78 #define DEFAULT_LOC "/lib/firmware/dgap/"
79
80 struct image_info       *image_list;
81 int                     nimages, count;
82
83 struct image_info images[] = {
84 {IBIOS, T_EPC,      SUBTYPE, 0, NULL, "EPC/X",  "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
85 {IFEP,  T_EPC,      SUBTYPE, 0, NULL, "EPC/X",  "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
86 {ICONC, T_EPC,      SUBTYPE, 0, NULL, "EPC/X",  "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
87
88 {IBIOS, T_CX,       SUBTYPE, 0, NULL, "C/X",    "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
89 {IFEP,  T_CX,       SUBTYPE, 0, NULL, "C/X",    "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
90
91 {IBIOS, T_CX,       T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
92 {IFEP,  T_CX,       T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
93
94 {ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",    "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
95 {ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",    "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
96 {ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",    "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
97
98 {IBIOS, FAMILY,   T_PCXR, 0, NULL, "PCXR",      "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
99 {IFEP,  FAMILY,   T_PCXR, 0,  NULL,  "PCXR",    "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0  },
100
101 {IBIOS, T_PCLITE,   SUBTYPE, 0, NULL, "X/em",   "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
102 {IFEP,  T_PCLITE,   SUBTYPE, 0,  NULL,  "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0  },
103
104 {IBIOS, T_EPC,      T_PCIBUS, 0, NULL, "PCI",   "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
105 {IFEP,  T_EPC,      T_PCIBUS, 0, NULL, "PCI",   "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
106 {ICONFIG, 0,        0, 0, NULL,         NULL,   "dgap.conf",    "/etc/dgap.conf", 0 },
107
108 /* IBAD/NULL entry indicating end-of-table */
109
110 {IBAD,  0,     0, 0,  NULL,  NULL, NULL, NULL, 0 }
111
112 } ;
113
114 int     errorprint = 1;
115 int     nodldprint = 1;
116 int     debugflag;
117 int     fd;
118
119 struct downld_t *ip;    /* Image pointer in current image  */
120 struct downld_t *dp;    /* conc. download */
121
122
123 /*
124  * The same for either the FEP or the BIOS. 
125  *  Append the downldio header, issue the ioctl, then free
126  *  the buffer.  Not horribly CPU efficient, but quite RAM efficient.
127  */
128
129 void squirt(int req_type, int bdid, struct image_info *ii)
130 {
131         struct downldio *dliop;
132         int size_buf;
133         int sfd;
134         struct stat sb;
135
136         /*
137          * If this binary comes from a file, stat it to see how
138          * large it is. Yes, we intentionally do this each
139          * time for the binary may change between loads. 
140          */
141
142         if (ii->pathname) {
143                 sfd = open(ii->pathname, O_RDONLY);
144
145                 if (sfd < 0 ) {
146                         myperror(ii->pathname);
147                         goto squirt_end; 
148                 }
149
150                 if (fstat(sfd, &sb) == -1 ) {
151                         myperror(ii->pathname);
152                         goto squirt_end;
153                 }
154
155                 ii->len = sb.st_size ; 
156         }
157
158         size_buf = ii->len + sizeof(struct downldio);
159
160         /*
161          * This buffer will be freed at the end of this function.  It is
162          * not resilient and should be around only long enough for the d/l
163          * to happen.
164          */
165         dliop = (struct downldio *) malloc(size_buf);
166
167         if (dliop == NULL) {
168                 fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n", 
169                         pgm, size_buf);
170                 exit (1);
171         }
172
173         /* Now, stick the image in fepimage.  This can come from either
174          *  the compiled-in image or from the filesystem.
175          */
176         if (ii->pathname)
177                 read(sfd, dliop->image.fi.fepimage, ii->len);
178         else
179                 memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
180
181         dliop->req_type = req_type;
182         dliop->bdid = bdid;
183
184         dliop->image.fi.len = ii->len;
185
186         if (debugflag)
187                 printf("sending %d bytes of %s %s from %s\n",
188                         ii->len, 
189                         (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
190                         ii->name ? ii->name : "",
191                         (ii->pathname) ? ii->pathname : "internal image" );
192
193         if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
194                 if(errorprint) {
195                         fprintf(stderr,
196                                 "%s: warning - download ioctl failed\n",pgm);
197                         errorprint = 0;
198                 }
199                 sleep(2);
200         }
201
202 squirt_end:
203
204         if (ii->pathname) {
205                 close(sfd);
206         }
207         free(dliop);
208 }
209
210
211 /*
212  *  See if we need to reload the download image in core 
213  * 
214  */
215 void consider_file_rescan(struct image_info *ii)
216 {
217         int sfd ; 
218         int len ; 
219         struct stat     sb;
220
221         /* This operation only makes sense when we're working from a file */
222
223         if (ii->pathname) {
224
225                 sfd = open (ii->pathname, O_RDONLY) ;
226                 if (sfd < 0 ) {
227                         myperror(ii->pathname);
228                         exit(1) ;
229                 }
230
231                 if( fstat(sfd,&sb) == -1 ) {
232                         myperror(ii->pathname);
233                         exit(1);
234                 }
235                 
236                 /* If the file hasn't changed since we last did this, 
237                  * and we have not done a free() on the image, bail  
238                  */
239                 if (ii->image && (sb.st_mtime == ii->mtime))
240                         goto end_rescan;
241
242                 ii->len = len = sb.st_size ; 
243
244                 /* Record the timestamp of the file */
245                 ii->mtime = sb.st_mtime;
246
247                 /* image should be NULL unless there is an image malloced
248                  * in already.  Before we malloc again, make sure we don't
249                  * have a memory leak.
250                  */
251                 if ( ii->image ) {
252                         free( ii->image ); 
253                         /* ii->image = NULL; */ /* not necessary */
254                 }
255
256                 /* This image will be kept only long enough for the 
257                  * download to happen.  After sending the last block, 
258                  * it will be freed
259                  */
260                 ii->image = malloc(len) ;
261
262                 if (ii->image == NULL) {
263                         fprintf(stderr,
264                                 "%s: can't get %d bytes of memory; aborting\n",
265                                  pgm, len);
266                         exit (1);
267                 }
268
269                 if (read(sfd, ii->image, len) < len) {
270                         fprintf(stderr,"%s: read error on %s; aborting\n", 
271                                 pgm, ii->pathname);
272                         exit (1);
273                 }
274
275 end_rescan:
276                 close(sfd);
277                 
278         }
279 }
280
281 /*
282  * Scan for images to match the driver requests
283  */
284
285 struct image_info * find_conc_image()
286 {
287         int x ; 
288         struct image_info *i = NULL ; 
289
290         for ( x = 0; x < nimages; x++ ) {
291                 i=&image_list[x];
292                                 
293                 if(i->type != ICONC)
294                         continue;
295
296                 consider_file_rescan(i) ;
297
298                 ip = (struct downld_t *) image_list[x].image;
299                 if (ip == NULL) continue;
300
301                 /*
302                  * When I removed Clusterport, I kept only the code that I
303                  * was SURE wasn't ClusterPort.  We may not need the next two
304                  * lines of code.
305                  */
306                 if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
307                         return i;
308         } 
309         return NULL ; 
310 }
311
312
313 int main(int argc, char **argv)
314 {
315         struct downldio dlio;
316         int             offset, bsize;
317         int             x;
318         char            *down, *image, *fname;
319         struct image_info *ii;
320
321         pgm = argv[0];
322         dp = &dlio.image.dl;            /* conc. download */
323
324         while((argc > 2) && !strcmp(argv[1],"-d")) {
325                 debugflag++ ;
326                 argc-- ;
327                 argv++ ;
328         }
329
330         if(argc < 2) {
331                 fprintf(stderr,
332                         "usage: %s download-device [image-file] ...\n",
333                         pgm);
334                 exit(1);
335         }
336
337
338
339         /*
340          * Daemonize, unless debugging is turned on.
341          */
342         if (debugflag == 0) {
343                 switch (fork())
344                 {
345                 case 0:
346                         break;
347
348                 case -1:
349                         return 1;
350
351                 default:
352                         return 0;
353                 }
354
355                 setsid();
356
357                 /*
358                  * The child no longer needs "stdin", "stdout", or "stderr",
359                  * and should not block processes waiting for them to close.
360                  */
361                 fclose(stdin);
362                 fclose(stdout);
363                 fclose(stderr);
364
365         }
366
367         while (1) {
368                 if( (fd = open(argv[1], O_RDWR)) == -1 ) {
369                         sleep(1);
370                 }
371                 else
372                         break;
373         }
374
375         /*
376         ** create a list of images to search through when trying to match
377         ** requests from the driver.  Put images from the command line in
378         ** the list before built in images so that the command line images
379         ** can override the built in ones.
380         */
381         
382         /* allocate space for the list */
383
384         nimages = argc - 2;
385
386         /* count the number of default list entries */
387
388         for (count = 0; images[count].type != IBAD; ++count) ;
389
390         nimages += count;
391
392         /* Really should just remove the variable "image_list".... robertl */
393         image_list = images ; 
394            
395         /* get the images from the command line */
396         for(x = 2; x < argc; x++) {
397                 int xx; 
398
399                 /*
400                  * strip off any leading path information for 
401                  * determining file type 
402                  */
403                 if( (fname = strrchr(argv[x],'/')) == NULL)
404                         fname = argv[x];
405                 else
406                         fname++;        /* skip the slash */
407
408                 for (xx = 0; xx < count; xx++) {
409                         if (strcmp(fname, images[xx].fname) == 0 ) { 
410                                 images[xx].pathname = argv[x];
411
412                                 /* image should be NULL until */
413                                 /* space is malloced */
414                                 images[xx].image = NULL ;  
415                         }
416                 }
417         }
418
419         sleep(3);
420         
421         /*
422         ** Endless loop: get a request from the fep, and service that request.
423         */
424         for(;;) {
425                 /* get the request */
426                 if (debugflag)
427                         printf("b4 get ioctl...");
428         
429                 if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
430                         if (errorprint) {
431                                 fprintf(stderr,
432                                         "%s: warning - download ioctl failed\n",
433                                         pgm);
434                                 errorprint = 0;
435                         }
436                         sleep(2);
437                 } else {
438                         if (debugflag)
439                                 printf("dlio.req_type is %d bd %d\n",
440                                         dlio.req_type,dlio.bdid);
441         
442                         switch(dlio.req_type) {
443                         case DLREQ_BIOS:
444                                 /*
445                                 ** find the bios image for this type
446                                 */
447                                 for ( x = 0; x < nimages; x++ ) {
448                                         if(image_list[x].type != IBIOS)
449                                                 continue;
450         
451                                         if ((dlio.image.fi.type & FAMILY) == 
452                                                 image_list[x].family) {
453                                                 
454                                                 if ( image_list[x].family == T_CX   ) { 
455                                                         if ((dlio.image.fi.type & BUSTYPE) 
456                                                                 == T_PCIBUS ) {
457                                                                 if ( image_list[x].subtype 
458                                                                         == T_PCIBUS )
459                                                                         break;
460                                                         }
461                                                         else { 
462                                                                 break;
463                                                         }
464                                                 }
465                                                 else if ( image_list[x].family == T_EPC ) {
466                                                 /* If subtype of image is T_PCIBUS, it is */
467                                                 /* a PCI EPC image, so the board must */
468                                                 /* have bus type T_PCIBUS to match */
469                                                         if ((dlio.image.fi.type & BUSTYPE) 
470                                                                 == T_PCIBUS ) {
471                                                                 if ( image_list[x].subtype 
472                                                                         == T_PCIBUS )
473                                                                         break;
474                                                         }
475                                                         else { 
476                                                         /* NON PCI EPC doesn't use PCI image */
477                                                                 if ( image_list[x].subtype 
478                                                                         != T_PCIBUS )
479                                                                         break;
480                                                         }
481                                                 }
482                                                 else
483                                                         break;
484                                         }
485                                         else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
486                                                 /* PCXR board will break out of the loop here */
487                                                 if ( image_list[x].subtype == T_PCXR   ) { 
488                                                                         break;
489                                                 }
490                                         }
491                                 }
492         
493                                 if ( x >= nimages) {
494                                         /*
495                                         ** no valid images exist
496                                         */
497                                         if(nodldprint) {
498                                                 fprintf(stderr,
499                                                 "%s: cannot find correct BIOS image\n",
500                                                         pgm);
501                                                 nodldprint = 0;
502                                         }
503                                         dlio.image.fi.type = -1;
504                                         if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
505                                                 if (errorprint) {
506                                                         fprintf(stderr,
507                                                         "%s: warning - download ioctl failed\n",
508                                                         pgm);
509                                                         errorprint = 0;
510                                                 }
511                                                 sleep(2);
512                                         }
513                                         break;
514                                 }
515                                 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
516                                 break ;
517         
518                         case DLREQ_FEP:
519                                 /*
520                                 ** find the fep image for this type
521                                 */
522                                 for ( x = 0; x < nimages; x++ ) {
523                                         if(image_list[x].type != IFEP)
524                                                 continue;
525                                         if( (dlio.image.fi.type & FAMILY) == 
526                                                 image_list[x].family ) {
527                                                 if ( image_list[x].family == T_CX   ) { 
528                                                         /* C/X PCI board */
529                                                         if ((dlio.image.fi.type & BUSTYPE) 
530                                                                 == T_PCIBUS ) {
531                                                                 if ( image_list[x].subtype
532                                                                         == T_PCIBUS )
533                                                                         break;
534                                                         }
535                                                         else { 
536                                                         /* Regular CX */
537                                                                 break;
538                                                         }
539                                                 }
540                                                 else if ( image_list[x].family == T_EPC   )  {
541                                                 /* If subtype of image is T_PCIBUS, it is */
542                                                 /* a PCI EPC image, so the board must */
543                                                 /* have bus type T_PCIBUS to match */
544                                                         if ((dlio.image.fi.type & BUSTYPE) 
545                                                                 == T_PCIBUS ) {
546                                                                 if ( image_list[x].subtype 
547                                                                         == T_PCIBUS )
548                                                                         break;
549                                                         }
550                                                         else { 
551                                                         /* NON PCI EPC doesn't use PCI image */
552                                                                 if ( image_list[x].subtype 
553                                                                         != T_PCIBUS )
554                                                                         break;
555                                                         }
556                                                 }
557                                                 else
558                                                         break;
559                                         }
560                                         else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
561                                                 /* PCXR board will break out of the loop here */
562                                                 if ( image_list[x].subtype == T_PCXR   ) { 
563                                                                         break;
564                                                 }
565                                         }
566                                 }
567         
568                                 if ( x >= nimages) {
569                                         /*
570                                         ** no valid images exist
571                                         */
572                                         if(nodldprint) {
573                                                 fprintf(stderr,
574                                                 "%s: cannot find correct FEP image\n",
575                                                         pgm);
576                                                 nodldprint = 0;
577                                         }
578                                         dlio.image.fi.type=-1;
579                                         if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
580                                                 if(errorprint) {
581                                                         fprintf(stderr,
582                                                 "%s: warning - download ioctl failed\n",
583                                                                 pgm);
584                                                         errorprint=0;
585                                                 }
586                                                 sleep(2);
587                                         }
588                                         break;
589                                 }
590                                 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
591                                 break;
592
593                         case DLREQ_DEVCREATE:
594                                 {
595                                         char string[1024];
596 #if 0
597                                         sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
598 #endif
599                                         sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
600                                         system(string);
601
602                                         if (debugflag)
603                                                 printf("Created Devices.\n");
604                                         if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
605                                                 if(errorprint) {
606                                                         fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
607                                                         errorprint = 0;
608                                                 }
609                                                 sleep(2);
610                                         }
611                                         if (debugflag)
612                                                 printf("After ioctl set - Created Device.\n");
613                                 }
614
615                                 break;
616         
617                         case DLREQ_CONFIG:
618                                 for ( x = 0; x < nimages; x++ ) {
619                                         if(image_list[x].type != ICONFIG)
620                                                 continue;
621                                         else
622                                                 break;
623                                 }
624
625                                 if ( x >= nimages) {
626                                         /*
627                                         ** no valid images exist
628                                         */
629                                         if(nodldprint) {
630                                                 fprintf(stderr,
631                                                 "%s: cannot find correct CONFIG image\n",
632                                                         pgm);
633                                                 nodldprint = 0;
634                                         }
635                                         dlio.image.fi.type=-1;
636                                         if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
637                                                 if(errorprint) {
638                                                         fprintf(stderr,
639                                                 "%s: warning - download ioctl failed\n",
640                                                                 pgm);
641                                                         errorprint=0;
642                                                 }
643                                                 sleep(2);
644                                         }
645                                         break;
646                                 }
647
648                                 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
649                                 break;
650
651                         case DLREQ_CONC:
652                                 /*
653                                 ** find the image needed for this download
654                                 */
655                                 if ( dp->dl_seq == 0 ) {
656                                         /*
657                                         ** find image for hardware rev range
658                                         */
659                                         for ( x = 0; x < nimages; x++ ) {
660                                                 ii=&image_list[x];
661                 
662                                                 if(image_list[x].type != ICONC)
663                                                         continue;
664                 
665                                                 consider_file_rescan(ii) ;
666                 
667                                                 ip = (struct downld_t *) image_list[x].image;
668                                                 if (ip == NULL) continue;
669                 
670                                                 /*
671                                                  * When I removed Clusterport, I kept only the
672                                                  * code that I was SURE wasn't ClusterPort.
673                                                  * We may not need the next four lines of code.
674                                                  */
675
676                                                 if ((dp->dl_type != 'P' ) &&
677                                                  (ip->dl_lrev <= dp->dl_lrev ) && 
678                                                  ( dp->dl_lrev <= ip->dl_hrev))
679                                                         break;
680                                         }
681                                     
682                                         if ( x >= nimages ) {
683                                                 /*
684                                                 ** No valid images exist
685                                                 */
686                                                 if(nodldprint) {
687                                                         fprintf(stderr,
688                                                 "%s: cannot find correct download image %d\n",
689                                                                 pgm, dp->dl_lrev);
690                                                         nodldprint=0;
691                                                 }
692                                                 continue;
693                                         }
694                                     
695                                 } else {
696                                         /*
697                                         ** find image version required
698                                         */
699                                         if ((ii = find_conc_image()) == NULL ) {
700                                                 /*
701                                                 ** No valid images exist
702                                                 */
703                                                 fprintf(stderr,
704                                                 "%s: can't find rest of download image??\n",
705                                                         pgm);
706                                                 continue;
707                                         }
708                                 }
709                         
710                                 /*
711                                 ** download block of image
712                                 */
713                         
714                                 offset = 1024 * dp->dl_seq;
715                                 
716                                 /*
717                                 ** test if block requested within image
718                                 */
719                                 if ( offset < ii->len ) { 
720         
721                                         /*
722                                         ** if it is, determine block size, set segment,
723                                         ** set size, set pointers, and copy block
724                                         */
725                                         if (( bsize = ii->len - offset ) > 1024 )
726                                                 bsize = 1024;
727                                     
728                                         /*
729                                         ** copy image version info to download area
730                                         */
731                                         dp->dl_srev = ip->dl_srev;
732                                         dp->dl_lrev = ip->dl_lrev;
733                                         dp->dl_hrev = ip->dl_hrev;
734                                     
735                                         dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
736                                         dp->dl_size = bsize;
737                                     
738                                         down = (char *)&dp->dl_data[0];
739                                         image = (char *)((char *)ip + offset);
740         
741                                         memcpy(down, image, bsize);
742                                 } 
743                                 else {
744                                         /*
745                                         ** Image has been downloaded, set segment and
746                                         ** size to indicate no more blocks
747                                         */
748                                         dp->dl_seg = ip->dl_seg;
749                                         dp->dl_size = 0;
750         
751                                         /* Now, we can release the concentrator */
752                                         /* image from memory if we're running  */
753                                         /* from filesystem images */
754                 
755                                         if (ii->pathname)
756                                                 if (ii->image) {
757                                                         free(ii->image);
758                                                         ii->image = NULL ; 
759                                                 } 
760                                 }
761                         
762                                 if (debugflag)
763                                                 printf(
764                                                 "sending conc dl section %d to %s from %s\n",
765                                                         dp->dl_seq, ii->name,
766                                                 ii->pathname ? ii->pathname : "Internal Image");
767                 
768                                 if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
769                                         if (errorprint) {
770                                                 fprintf(stderr,
771                                                 "%s: warning - download ioctl failed\n",
772                                                         pgm);
773                                                 errorprint=0;
774                                         }
775                                         sleep(2);
776                                 }
777                                 break;
778                         } /* switch */
779                 }
780                 if (debugflag > 1) {
781                         printf("pausing: "); fflush(stdout);
782                         fflush(stdin);
783                         while(getchar() != '\n');
784                                 printf("continuing\n");
785                 }
786         }
787 }
788
789 /*
790 ** myperror()
791 **
792 **  Same as normal perror(), but places the program name at the beginning
793 **  of the message.
794 */
795 void myperror(char *s)
796 {
797         fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));
798 }