2 * Copyright 2003 Digi International (www.digi.com)
3 * Scott H Kilau <Scott_Kilau at digi dot com>
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)
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.
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.
19 * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
25 ** This is the daemon that sends the fep, bios, and concentrator images
26 ** from user space to the driver.
28 ** If the file changes in the middle of the download, you probably
29 ** will get what you deserve.
36 #include <sys/types.h>
38 #include <sys/errno.h>
40 #include "dgap_types.h"
42 #include "dgap_fep5.h"
44 #include "dgap_downld.h"
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.
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 */
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 */
78 #define DEFAULT_LOC "/lib/firmware/dgap/"
80 struct image_info
*image_list
;
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 },
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 },
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 },
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 },
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 },
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 },
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 },
108 /* IBAD/NULL entry indicating end-of-table */
110 {IBAD
, 0, 0, 0, NULL
, NULL
, NULL
, NULL
, 0 }
119 struct downld_t
*ip
; /* Image pointer in current image */
120 struct downld_t
*dp
; /* conc. download */
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.
129 void squirt(int req_type
, int bdid
, struct image_info
*ii
)
131 struct downldio
*dliop
;
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.
143 sfd
= open(ii
->pathname
, O_RDONLY
);
146 myperror(ii
->pathname
);
150 if (fstat(sfd
, &sb
) == -1 ) {
151 myperror(ii
->pathname
);
155 ii
->len
= sb
.st_size
;
158 size_buf
= ii
->len
+ sizeof(struct downldio
);
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
165 dliop
= (struct downldio
*) malloc(size_buf
);
168 fprintf(stderr
,"%s: can't get %d bytes of memory; aborting\n",
173 /* Now, stick the image in fepimage. This can come from either
174 * the compiled-in image or from the filesystem.
177 read(sfd
, dliop
->image
.fi
.fepimage
, ii
->len
);
179 memcpy(dliop
->image
.fi
.fepimage
, ii
->image
, ii
->len
);
181 dliop
->req_type
= req_type
;
184 dliop
->image
.fi
.len
= ii
->len
;
187 printf("sending %d bytes of %s %s from %s\n",
189 (ii
->type
== IFEP
) ? "FEP" : (ii
->type
== IBIOS
) ? "BIOS" : "CONFIG",
190 ii
->name
? ii
->name
: "",
191 (ii
->pathname
) ? ii
->pathname
: "internal image" );
193 if (ioctl(fd
, DIGI_DLREQ_SET
, (char *) dliop
) == -1) {
196 "%s: warning - download ioctl failed\n",pgm
);
212 * See if we need to reload the download image in core
215 void consider_file_rescan(struct image_info
*ii
)
221 /* This operation only makes sense when we're working from a file */
225 sfd
= open (ii
->pathname
, O_RDONLY
) ;
227 myperror(ii
->pathname
);
231 if( fstat(sfd
,&sb
) == -1 ) {
232 myperror(ii
->pathname
);
236 /* If the file hasn't changed since we last did this,
237 * and we have not done a free() on the image, bail
239 if (ii
->image
&& (sb
.st_mtime
== ii
->mtime
))
242 ii
->len
= len
= sb
.st_size
;
244 /* Record the timestamp of the file */
245 ii
->mtime
= sb
.st_mtime
;
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.
253 /* ii->image = NULL; */ /* not necessary */
256 /* This image will be kept only long enough for the
257 * download to happen. After sending the last block,
260 ii
->image
= malloc(len
) ;
262 if (ii
->image
== NULL
) {
264 "%s: can't get %d bytes of memory; aborting\n",
269 if (read(sfd
, ii
->image
, len
) < len
) {
270 fprintf(stderr
,"%s: read error on %s; aborting\n",
282 * Scan for images to match the driver requests
285 struct image_info
* find_conc_image()
288 struct image_info
*i
= NULL
;
290 for ( x
= 0; x
< nimages
; x
++ ) {
296 consider_file_rescan(i
) ;
298 ip
= (struct downld_t
*) image_list
[x
].image
;
299 if (ip
== NULL
) continue;
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
306 if ((dp
->dl_type
!= 'P' ) && ( ip
->dl_srev
== dp
->dl_srev
))
313 int main(int argc
, char **argv
)
315 struct downldio dlio
;
318 char *down
, *image
, *fname
;
319 struct image_info
*ii
;
322 dp
= &dlio
.image
.dl
; /* conc. download */
324 while((argc
> 2) && !strcmp(argv
[1],"-d")) {
332 "usage: %s download-device [image-file] ...\n",
340 * Daemonize, unless debugging is turned on.
342 if (debugflag
== 0) {
358 * The child no longer needs "stdin", "stdout", or "stderr",
359 * and should not block processes waiting for them to close.
368 if( (fd
= open(argv
[1], O_RDWR
)) == -1 ) {
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.
382 /* allocate space for the list */
386 /* count the number of default list entries */
388 for (count
= 0; images
[count
].type
!= IBAD
; ++count
) ;
392 /* Really should just remove the variable "image_list".... robertl */
395 /* get the images from the command line */
396 for(x
= 2; x
< argc
; x
++) {
400 * strip off any leading path information for
401 * determining file type
403 if( (fname
= strrchr(argv
[x
],'/')) == NULL
)
406 fname
++; /* skip the slash */
408 for (xx
= 0; xx
< count
; xx
++) {
409 if (strcmp(fname
, images
[xx
].fname
) == 0 ) {
410 images
[xx
].pathname
= argv
[x
];
412 /* image should be NULL until */
413 /* space is malloced */
414 images
[xx
].image
= NULL
;
422 ** Endless loop: get a request from the fep, and service that request.
425 /* get the request */
427 printf("b4 get ioctl...");
429 if (ioctl(fd
,DIGI_DLREQ_GET
, &dlio
) == -1 ) {
432 "%s: warning - download ioctl failed\n",
439 printf("dlio.req_type is %d bd %d\n",
440 dlio
.req_type
,dlio
.bdid
);
442 switch(dlio
.req_type
) {
445 ** find the bios image for this type
447 for ( x
= 0; x
< nimages
; x
++ ) {
448 if(image_list
[x
].type
!= IBIOS
)
451 if ((dlio
.image
.fi
.type
& FAMILY
) ==
452 image_list
[x
].family
) {
454 if ( image_list
[x
].family
== T_CX
) {
455 if ((dlio
.image
.fi
.type
& BUSTYPE
)
457 if ( image_list
[x
].subtype
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
)
471 if ( image_list
[x
].subtype
476 /* NON PCI EPC doesn't use PCI image */
477 if ( image_list
[x
].subtype
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
) {
495 ** no valid images exist
499 "%s: cannot find correct BIOS image\n",
503 dlio
.image
.fi
.type
= -1;
504 if (ioctl(fd
, DIGI_DLREQ_SET
, &dlio
) == -1) {
507 "%s: warning - download ioctl failed\n",
515 squirt(dlio
.req_type
, dlio
.bdid
, &image_list
[x
]);
520 ** find the fep image for this type
522 for ( x
= 0; x
< nimages
; x
++ ) {
523 if(image_list
[x
].type
!= IFEP
)
525 if( (dlio
.image
.fi
.type
& FAMILY
) ==
526 image_list
[x
].family
) {
527 if ( image_list
[x
].family
== T_CX
) {
529 if ((dlio
.image
.fi
.type
& BUSTYPE
)
531 if ( image_list
[x
].subtype
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
)
546 if ( image_list
[x
].subtype
551 /* NON PCI EPC doesn't use PCI image */
552 if ( image_list
[x
].subtype
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
) {
570 ** no valid images exist
574 "%s: cannot find correct FEP image\n",
578 dlio
.image
.fi
.type
=-1;
579 if( ioctl(fd
,DIGI_DLREQ_SET
,&dlio
) == -1 ) {
582 "%s: warning - download ioctl failed\n",
590 squirt(dlio
.req_type
, dlio
.bdid
, &image_list
[x
]);
593 case DLREQ_DEVCREATE
:
597 sprintf(string
, "%s /proc/dgap/%d/mknod", DEFSHELL
, dlio
.bdid
);
599 sprintf(string
, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL
, dlio
.bdid
);
603 printf("Created Devices.\n");
604 if (ioctl(fd
, DIGI_DLREQ_SET
, &dlio
) == -1 ) {
606 fprintf(stderr
, "%s: warning - DEVCREATE ioctl failed\n",pgm
);
612 printf("After ioctl set - Created Device.\n");
618 for ( x
= 0; x
< nimages
; x
++ ) {
619 if(image_list
[x
].type
!= ICONFIG
)
627 ** no valid images exist
631 "%s: cannot find correct CONFIG image\n",
635 dlio
.image
.fi
.type
=-1;
636 if (ioctl(fd
, DIGI_DLREQ_SET
, &dlio
) == -1 ) {
639 "%s: warning - download ioctl failed\n",
648 squirt(dlio
.req_type
, dlio
.bdid
, &image_list
[x
]);
653 ** find the image needed for this download
655 if ( dp
->dl_seq
== 0 ) {
657 ** find image for hardware rev range
659 for ( x
= 0; x
< nimages
; x
++ ) {
662 if(image_list
[x
].type
!= ICONC
)
665 consider_file_rescan(ii
) ;
667 ip
= (struct downld_t
*) image_list
[x
].image
;
668 if (ip
== NULL
) continue;
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.
676 if ((dp
->dl_type
!= 'P' ) &&
677 (ip
->dl_lrev
<= dp
->dl_lrev
) &&
678 ( dp
->dl_lrev
<= ip
->dl_hrev
))
682 if ( x
>= nimages
) {
684 ** No valid images exist
688 "%s: cannot find correct download image %d\n",
697 ** find image version required
699 if ((ii
= find_conc_image()) == NULL
) {
701 ** No valid images exist
704 "%s: can't find rest of download image??\n",
711 ** download block of image
714 offset
= 1024 * dp
->dl_seq
;
717 ** test if block requested within image
719 if ( offset
< ii
->len
) {
722 ** if it is, determine block size, set segment,
723 ** set size, set pointers, and copy block
725 if (( bsize
= ii
->len
- offset
) > 1024 )
729 ** copy image version info to download area
731 dp
->dl_srev
= ip
->dl_srev
;
732 dp
->dl_lrev
= ip
->dl_lrev
;
733 dp
->dl_hrev
= ip
->dl_hrev
;
735 dp
->dl_seg
= (64 * dp
->dl_seq
) + ip
->dl_seg
;
738 down
= (char *)&dp
->dl_data
[0];
739 image
= (char *)((char *)ip
+ offset
);
741 memcpy(down
, image
, bsize
);
745 ** Image has been downloaded, set segment and
746 ** size to indicate no more blocks
748 dp
->dl_seg
= ip
->dl_seg
;
751 /* Now, we can release the concentrator */
752 /* image from memory if we're running */
753 /* from filesystem images */
764 "sending conc dl section %d to %s from %s\n",
765 dp
->dl_seq
, ii
->name
,
766 ii
->pathname
? ii
->pathname
: "Internal Image");
768 if (ioctl(fd
, DIGI_DLREQ_SET
, &dlio
) == -1 ) {
771 "%s: warning - download ioctl failed\n",
781 printf("pausing: "); fflush(stdout
);
783 while(getchar() != '\n');
784 printf("continuing\n");
792 ** Same as normal perror(), but places the program name at the beginning
795 void myperror(char *s
)
797 fprintf(stderr
,"%s: %s: %s.\n",pgm
, s
, strerror(errno
));