K&R style function removal. Update functions to ANSI style.
[dragonfly.git] / sbin / atm / fore_dnld / fore_dnld.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sbin/atm/fore_dnld/fore_dnld.c,v 1.6.2.2 2000/12/11 01:03:24 obrien Exp $
27  *      @(#) $DragonFly: src/sbin/atm/fore_dnld/fore_dnld.c,v 1.4 2003/09/28 14:39:16 hmp Exp $
28  */
29
30 /*
31  * User utilities
32  * --------------
33  *
34  * Download (pre)processed microcode into Fore Series-200 host adapter
35  * Interact with i960 uart on Fore Series-200 host adapter
36  *
37  */
38
39 #include <sys/param.h>
40 #include <sys/mman.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <net/if.h>
44 #include <netatm/atm.h>
45 #include <netatm/atm_if.h>
46 #include <netatm/atm_sap.h>
47 #include <netatm/atm_sys.h>
48 #include <netatm/atm_ioctl.h>
49 #include <dev/atm/hfa/fore.h>
50 #include <dev/atm/hfa/fore_aali.h>
51 #include <dev/atm/hfa/fore_slave.h>
52
53 #include <ctype.h>
54 #include <fcntl.h>
55 #include <paths.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #if (defined(BSD) && (BSD >= 199103))
60 #include <termios.h>
61 #else
62 #include <termio.h>
63 #endif  /* !BSD */
64 #include <unistd.h>
65
66 extern u_char pca200e_microcode[];
67 extern int pca200e_microcode_size;
68
69 #ifdef sun
70 #define DEV_NAME "/dev/sbus%d"
71 #endif  /* sun */
72 #if (defined(BSD) && (BSD >= 199103))
73 #define DEV_NAME _PATH_KMEM
74 #endif  /* BSD */
75
76 #define MAX_CHECK       60
77
78 int     comm_mode = 0;
79 char    *progname;
80
81 int     tty;
82 cc_t    vmin, vtime;
83 #if (defined(BSD) && (BSD >= 199103))
84 struct termios sgtty;
85 #define TCSETA  TIOCSETA
86 #define TCGETA  TIOCGETA
87 #else
88 struct termio sgtty;
89 #endif  /* !BSD */
90
91 int     endian = 0;
92 int     verbose = 0;
93 int     reset = 0;
94
95 char    line[132];
96 int     lineptr = 0;
97
98 Mon960 *Uart;
99
100 void
101 delay(cnt)
102         int     cnt;
103 {
104         usleep(cnt);
105 }
106
107 unsigned long
108 CP_READ ( unsigned long val )
109 {
110         if ( endian )
111                 return ( ntohl ( val ) );
112         else
113                 return ( val );
114 }
115
116 unsigned long
117 CP_WRITE ( unsigned long val )
118 {
119         if ( endian )
120                 return ( htonl ( val ) );
121         else
122                 return ( val );
123 }
124
125 /*
126  * Print an error message and exit.
127  *
128  * Arguments:
129  *      none
130  *
131  * Returns:
132  *      none
133  */
134 void
135 error ( char *msg )
136 {
137         printf ( "%s\n", msg );
138         exit (1);
139 }
140
141 /*
142  * Get a byte for the uart and if printing, display it.
143  *
144  * Arguments:
145  *      prn                             Are we displaying characters
146  *
147  * Returns:
148  *      c                               Character from uart
149  */
150 char
151 getbyte ( int prn )
152 {
153         int     c;
154
155         while ( ! ( CP_READ(Uart->mon_xmithost) & UART_VALID ) )
156                 delay(10);
157
158         c = ( CP_READ(Uart->mon_xmithost) & UART_DATAMASK );
159         Uart->mon_xmithost = CP_WRITE(UART_READY);
160
161         /*
162          * We need to introduce a delay in here or things tend to hang...
163          */
164         delay(10000);
165
166         if ( lineptr >= sizeof(line) )
167                 lineptr = 0;
168
169         /*
170          * Save character into line
171          */
172         line[lineptr++] = c;
173
174         if (verbose) {
175                 if (isprint(c) || (c == '\n') || (c == '\r'))
176                         putc(c, stdout);
177         }
178         return ( c & 0xff );
179 }
180
181 /*
182  * Loop getting characters from uart into static string until eol. If printing,
183  * display the line retrieved.
184  *
185  * Arguments:
186  *      prn                             Are we displaying characters
187  *
188  * Returns:
189  *      none                            Line in global string 'line[]'
190  */
191 void
192 getline ( int prn )
193 {
194         char    c = '\0';
195         int     i = 0;
196
197         while ( c != '>' && c != '\n' && c != '\r' )
198         {
199                 c = getbyte(0);
200                 if ( ++i >= sizeof(line) )
201                 {
202                         if ( prn )
203                                 printf ( "%s", line );
204                         i = 0;
205                 }
206         }
207
208         /*
209          * Terminate line
210          */
211         line[lineptr] = 0;
212         lineptr = 0;
213
214 }
215
216 /*
217  * Send a byte to the i960
218  *
219  * Arguments:
220  *      c                               Character to send
221  *
222  * Returns:
223  *      none
224  */
225 void
226 xmit_byte ( unsigned char c, int dn )
227 {
228         int     val;
229
230         while ( CP_READ(Uart->mon_xmitmon) != UART_READY )
231         {
232                 if ( CP_READ(Uart->mon_xmithost) & UART_VALID )
233                         getbyte ( 0 );
234                 if ( !dn ) delay ( 10000 );
235         }
236         val = ( c | UART_VALID );
237         Uart->mon_xmitmon = CP_WRITE( val );
238         if ( !dn ) delay ( 10000 );
239         if ( CP_READ(Uart->mon_xmithost) & UART_VALID )
240                 getbyte ( 0 );
241
242 }
243
244 /*
245  * Transmit a line to the i960. Eol must be included as part of text to transmit.
246  *
247  * Arguments:
248  *      line                    Character string to transmit
249  *      len                     len of string. This allows us to include NULL's
250  *                                      in the string/block to be transmitted.
251  *
252  * Returns:
253  *      none
254  */
255 void
256 xmit_to_i960 ( char *line, int len, int dn )
257 {
258         int     i;
259
260         for ( i = 0; i < len; i++ )
261                 xmit_byte ( line[i], dn );
262 }
263
264 /*
265  * Send autobaud sequence to i960 monitor
266  *
267  * Arguments:
268  *      none
269  *
270  * Returns:
271  *      none
272  */
273 void
274 autobaud(void)
275 {
276         if ( strncmp ( line, "Mon960", 6 ) == 0 )
277                 xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 );
278 }
279
280 /*
281  * Reset tty to initial state
282  *
283  * Arguments:
284  *      ret             error code for exit()
285  *
286  * Returns:
287  *      none
288  *
289  */
290 void
291 finish ( int ret )
292 {
293         sgtty.c_lflag |= ( ICANON | ECHO );
294         sgtty.c_cc[VMIN] = vmin;
295         sgtty.c_cc[VTIME] = vtime;
296         ioctl ( tty, TCSETA, &sgtty );
297         exit ( ret );
298 }
299
300 /*
301  * Utility to strip off any leading path information from a filename
302  *
303  * Arguments:
304  *      path            pathname to strip
305  *
306  * Returns:
307  *      fname           striped filename
308  *
309  */
310 char *
311 basename ( char *path )
312 {
313         char *fname;
314
315         if ( ( fname = strrchr ( path, '/' ) ) != NULL )
316                 fname++;
317         else
318                 fname = path;
319
320         return ( fname );
321 }
322
323 /*
324  * ASCII constants
325  */
326 #define         SOH             001
327 #define         STX             002
328 #define         ETX             003
329 #define         EOT             004
330 #define         ENQ             005
331 #define         ACK             006
332 #define         LF              012
333 #define         CR              015
334 #define         NAK             025
335 #define         SYN             026
336 #define         CAN             030
337 #define         ESC             033
338
339 #define         NAKMAX          2
340 #define         ERRORMAX        10
341 #define         RETRYMAX        5
342
343 #define         CRCCHR          'C'
344 #define         CTRLZ           032
345
346 #define         BUFSIZE         128
347
348 #define         W               16
349 #define         B               8
350
351 /*
352  * crctab - CRC-16 constant array...
353  *     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
354  *     (ihnp4!umn-cs!hyper!mark)
355  */
356 unsigned short crctab[1<<B] = {
357     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
358     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
359     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
360     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
361     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
362     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
363     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
364     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
365     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
366     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
367     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
368     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
369     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
370     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
371     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
372     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
373     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
374     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
375     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
376     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
377     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
378     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
379     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
380     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
381     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
382     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
383     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
384     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
385     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
386     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
387     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
388     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
389     };
390
391 /*
392  * Hacked up xmodem protocol. Transmits the file 'filename' down to the i960
393  * using the xmodem protocol.
394  *
395  * Arguments:
396  *      filename                        name of file to transmit
397  *
398  * Returns:
399  *      0                               file transmitted
400  *      -1                              unable to send file
401  */
402 int
403 xmitfile ( char *filename )
404 {
405         int     fd;
406         int     numsect;
407         int     sectnum;
408         struct stat stb;
409         char    c;
410         char    sendresp;
411         int     crcmode = 0;
412         int     attempts = 0;
413         int     errors;
414         int     sendfin;
415         int     extrachr;
416         char    buf[BUFSIZE + 6];
417         char    blockbuf[BUFSIZE + 6];
418         int     bufcntr;
419         int     bbufcntr;
420         int     bufsize = BUFSIZE;
421         int     checksum;
422
423         /*
424          * Try opening file
425          */
426         if ( ( fd = open ( filename, O_RDONLY ) ) < 0 )
427         {
428                 return -1;
429         }
430         stat ( filename, &stb );
431
432         /*
433          * Determine number of 128 bytes sectors to transmit
434          */
435         numsect = ( stb.st_size / 128 ) + 1;
436
437         if ( verbose )
438                 fprintf ( stderr, "Downloading %d sectors from %s\n",
439                         numsect, filename );
440
441         /*
442          * Send DO'wnload' command to i960
443          */
444         xmit_to_i960 ( "do\r\n", 4, 0 );
445         /*
446          * Wait for response from i960 indicating download in progress
447          */
448         while ( strncmp ( line, "Downloading", 11 ) != 0 )
449                 getline ( verbose );
450         
451
452         /*
453          * Get startup character from i960
454          */
455         do {
456                 while ( ( c = getbyte(0) ) != NAK && c != CRCCHR )
457                         if ( ++attempts > NAKMAX )
458                                 error ( "Remote system not responding" );
459
460                 if ( c == CRCCHR )
461                         crcmode = 1;
462
463         } while ( c != NAK && c != CRCCHR );
464
465         sectnum = 1;
466         attempts = errors = sendfin = extrachr = 0;
467
468         /*
469          * Loop over each sector to be sent
470          */
471         do {
472                 if ( extrachr >= 128 )
473                 {
474                         extrachr = 0;
475                         numsect++;
476                 }
477
478                 if ( sectnum > 0 )
479                 {
480                         /*
481                          * Read a sectors worth of data from the file into
482                          * an internal buffer.
483                          */
484                         for ( bufcntr = 0; bufcntr < bufsize; )
485                         {
486                                 int n;
487                                 /*
488                                  * Check for EOF
489                                  */
490                                 if ( ( n = read ( fd, &c, 1 ) ) == 0 )
491                                 {
492                                         sendfin = 1;
493                                         if ( !bufcntr )
494                                                 break;
495                                         buf[bufcntr++] = CTRLZ;
496                                         continue;
497                                 }
498                                 buf[bufcntr++] = c;
499                         }
500                         if ( !bufcntr )
501                                 break;
502                 }
503
504                 /*
505                  * Fill in xmodem protocol values. Block size and sector number
506                  */
507                 bbufcntr = 0;
508                 blockbuf[bbufcntr++] = (bufsize == 1024) ? STX : SOH;
509                 blockbuf[bbufcntr++] = sectnum;
510                 blockbuf[bbufcntr++] = ~sectnum;
511
512                 checksum = 0;
513
514                 /*
515                  * Loop over the internal buffer computing the checksum of the
516                  * sector
517                  */
518                 for ( bufcntr = 0; bufcntr < bufsize; bufcntr++ )
519                 {
520                         blockbuf[bbufcntr++] = buf[bufcntr];
521
522                         if ( crcmode )
523                                 checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buf[bufcntr]];
524                         else
525                                 checksum = ((checksum + buf[bufcntr]) & 0xff);
526
527                 }
528
529                 /*
530                  * Place the checksum at the end of the transmit buffer
531                  */
532                 if ( crcmode )
533                 {
534                         checksum &= 0xffff;
535                         blockbuf[bbufcntr++] = ((checksum >> 8) & 0xff);
536                         blockbuf[bbufcntr++] = (checksum & 0xff);
537                 } else
538                         blockbuf[bbufcntr++] = checksum;
539
540                 attempts = 0;
541
542                 /*
543                  * Make several attempts to send the data to the i960
544                  */
545                 do
546                 {
547                         /*
548                          * Transmit the sector + protocol to the i960
549                          */
550                         xmit_to_i960 ( blockbuf, bbufcntr, 1 );
551
552                         /*
553                          * Inform user where we're at
554                          */
555                         if ( verbose )
556                                 printf ( "Sector %3d %3dk\r",
557                                     sectnum, (sectnum * bufsize) / 1024 );
558
559                         attempts++;
560                         /*
561                          * Get response from i960
562                          */
563                         sendresp = getbyte(0);
564
565                         /*
566                          * If i960 didn't like the sector
567                          */
568                         if ( sendresp != ACK )
569                         {
570                                 errors++;
571
572                                 /*
573                                  * Are we supposed to cancel the transfer?
574                                  */
575                                 if ( ( sendresp & 0x7f ) == CAN )
576                                         if ( getbyte(0) == CAN )
577                                                 error ( "Send canceled at user's request" );
578                         }
579
580                 } while ( ( sendresp != ACK ) && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) );
581
582                 /*
583                  * Next sector
584                  */
585                 sectnum++;
586
587         } while ( !sendfin && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) );
588
589         /*
590          * Did we expire all our allows attempts?
591          */
592         if ( attempts >= RETRYMAX )
593         {
594                 xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 );
595                 error ( "Remote system not responding" );
596         }
597
598         /*
599          * Check for too many transmission errors
600          */
601         if ( errors >= ERRORMAX )
602         {
603                 xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 );
604                 error ( "Too many errors in transmission" );
605         }
606
607         attempts = 0;
608
609         /*
610          * Indicate the transfer is complete
611          */
612         xmit_byte ( EOT, 1 );
613
614         /*
615          * Wait until i960 acknowledges us
616          */
617         while ( ( c = getbyte(0) ) != ACK && ( ++attempts < RETRYMAX ) )
618                 xmit_byte ( EOT, 1 );
619
620         if ( attempts >= RETRYMAX )
621                 error ( "Remote system not responding on completion" );
622
623         /*
624          * After download, we'll see a few more command 
625          * prompts as the CP does its stuff. Ignore them.
626          */
627         while ( strncmp ( line, "=>", 2 ) != 0 )
628                 getline ( verbose );
629
630         while ( strncmp ( line, "=>", 2 ) != 0 )
631                 getline ( verbose );
632
633         while ( strncmp ( line, "=>", 2 ) != 0 )
634                 getline ( verbose );
635
636         /*
637          * Tell the i960 to start executing the downloaded code
638          */
639         xmit_to_i960 ( "go\r\n", 4, 0 );
640
641         /*
642          * Get the messages the CP will spit out
643          * after the GO command.
644          */
645         getline ( verbose );
646         getline ( verbose );
647
648         close ( fd );
649
650         return ( 0 );
651 }
652
653
654 int
655 loadmicrocode ( u_char *ucode, int size, u_char *ram )
656 {
657         struct {
658                 u_long  Id;
659                 u_long  fver;
660                 u_long  start;
661                 u_long  entry;
662         } binhdr;
663 #ifdef sun
664         union {
665                 u_long  w;
666                 char    c[4];
667         } w1, w2;
668 #endif
669         int     n;
670         int     cnt = 0;
671         u_char  *bufp;
672         u_long  *lp;
673
674
675         /*
676          * Check that we understand this header
677          */
678         memcpy(&binhdr, ucode, sizeof(binhdr));
679         if ( strncmp ( (caddr_t)&binhdr.Id, "fore", 4 ) != 0 ) {
680                 fprintf ( stderr, "Unrecognized format in micorcode file." );
681                 return ( -1 );
682         }
683
684 #ifdef  sun
685         /*
686          * We always swap the SunOS microcode file...
687          */
688         endian = 1;
689
690         /*
691          * We need to swap the header start/entry words...
692          */
693         w1.w = binhdr.start;
694         for ( n = 0; n < sizeof(u_long); n++ )
695                 w2.c[3-n] = w1.c[n];
696         binhdr.start = w2.w;
697         w1.w = binhdr.entry;
698         for ( n = 0; n < sizeof(u_long); n++ )
699                 w2.c[3-n] = w1.c[n];
700         binhdr.entry = w2.w;
701 #endif  /* sun */
702
703         /*
704          * Set pointer to RAM load location
705          */
706         bufp = (ram + binhdr.start);
707
708         /*
709          * Load file
710          */
711         if ( endian ) {
712                 int     i;
713
714                 lp = (u_long *) ucode;
715                 /* Swap buffer */
716                 for ( i = 0; i < size / sizeof(long); i++ )
717 #ifndef sun
718                         lp[i] = CP_WRITE(lp[i]);
719 #else
720                 {
721                         int     j;
722
723                         w1.w = lp[i];
724                         for ( j = 0; j < 4; j++ )
725                                 w2.c[3-j] = w1.c[j];
726                         lp[i] = w2.w;
727                 }
728 #endif
729         }
730         bcopy ( (caddr_t)ucode, bufp, size );
731
732         /*
733          * With .bin extension, we need to specify start address on 'go'
734          * command.
735          */
736         {
737                 char    cmd[80];
738
739                 sprintf ( cmd, "go %lx\r\n", binhdr.entry );
740
741                 xmit_to_i960 ( cmd, strlen ( cmd ), 0 );
742
743                 while ( strncmp ( line, cmd, strlen(cmd) - 3 ) != 0 ) 
744                         getline ( verbose );
745
746                 if ( verbose )
747                         printf("\n");
748         }
749         return ( 0 );
750 }
751
752 int
753 sendbinfile ( char *fname, u_char *ram )
754 {
755         struct {
756                 u_long  Id;
757                 u_long  fver;
758                 u_long  start;
759                 u_long  entry;
760         } binhdr;
761 #ifdef sun
762         union {
763                 u_long  w;
764                 char    c[4];
765         } w1, w2;
766 #endif
767         int     fd;
768         int     n;
769         int     cnt = 0;
770         u_char  *bufp;
771         long    buffer[1024];
772
773         /*
774          * Try opening file
775          */
776         if ( ( fd = open ( fname, O_RDONLY ) ) < 0 )
777                 return ( -1 );
778
779         /*
780          * Read the .bin header from the file
781          */
782         if ( ( read ( fd, &binhdr, sizeof(binhdr) ) ) != sizeof(binhdr) )
783         {
784                 close ( fd );
785                 return ( -1 );
786         }
787
788         /*
789          * Check that we understand this header
790          */
791         if ( strncmp ( (caddr_t)&binhdr.Id, "fore", 4 ) != 0 ) {
792                 fprintf ( stderr, "Unrecognized format in micorcode file." );
793                 close ( fd );
794                 return ( -1 );
795         }
796
797 #ifdef  sun
798         /*
799          * We always swap the SunOS microcode file...
800          */
801         endian = 1;
802
803         /*
804          * We need to swap the header start/entry words...
805          */
806         w1.w = binhdr.start;
807         for ( n = 0; n < sizeof(u_long); n++ )
808                 w2.c[3-n] = w1.c[n];
809         binhdr.start = w2.w;
810         w1.w = binhdr.entry;
811         for ( n = 0; n < sizeof(u_long); n++ )
812                 w2.c[3-n] = w1.c[n];
813         binhdr.entry = w2.w;
814 #endif  /* sun */
815
816         /*
817          * Rewind the file
818          */
819         lseek ( fd, 0, 0 );
820
821         /*
822          * Set pointer to RAM load location
823          */
824         bufp = (ram + binhdr.start);
825
826         /*
827          * Load file
828          */
829         if ( endian ) {
830                 /*
831                  * Need to swap longs - copy file into temp buffer
832                  */
833                 while ( ( n = read ( fd, (char *)buffer, sizeof(buffer))) > 0 )
834                 {
835                         int     i;
836
837                         /* Swap buffer */
838                         for ( i = 0; i < sizeof(buffer) / sizeof(long); i++ )
839 #ifndef sun
840                                 buffer[i] = CP_WRITE(buffer[i]);
841 #else
842                         {
843                                 int     j;
844
845                                 w1.w = buffer[i];
846                                 for ( j = 0; j < 4; j++ )
847                                         w2.c[3-j] = w1.c[j];
848                                 buffer[i] = w2.w;
849                         }
850 #endif
851
852                         /*
853                          * Copy swapped buffer into CP RAM
854                          */
855                         cnt++;
856                         bcopy ( (caddr_t)buffer, bufp, n );
857                         if ( verbose )
858                                 printf ( "%d\r", cnt );
859                         bufp += n;
860                 }
861         } else {
862             while ( ( n = read ( fd, bufp, 128 ) ) > 0 )
863             {
864                 cnt++;
865                 if ( verbose )
866                         printf ( "%d\r", cnt );
867                 bufp += n;
868             }
869         }
870
871         /*
872          * With .bin extension, we need to specify start address on 'go'
873          * command.
874          */
875         {
876                 char    cmd[80];
877
878                 sprintf ( cmd, "go %lx\r\n", binhdr.entry );
879
880                 xmit_to_i960 ( cmd, strlen ( cmd ), 0 );
881
882                 while ( strncmp ( line, cmd, strlen(cmd) - 3 ) != 0 )
883                         getline ( verbose );
884
885                 if ( verbose )
886                         printf("\n");
887         }
888
889         close ( fd );
890         return ( 0 );
891 }
892
893
894 /*
895  * Program to download previously processed microcode to series-200 host adapter
896  */
897 int
898 main( int argc, char **argv )
899 {
900         int     fd;                     /* mmap for Uart */
901         u_char  *ram;                   /* pointer to RAM */
902         Mon960  *Mon;                   /* Uart */
903         Aali    *aap;
904         char    c;
905         int     i, err;
906         int     binary = 0;             /* Send binary file */
907         caddr_t buf;                    /* Ioctl buffer */
908         char    bus_dev[80];            /* Bus device to mmap on */
909         struct atminfreq req;
910         struct air_cfg_rsp *air;        /* Config info response structure */
911         int     buf_len;                /* Size of ioctl buffer */
912         char    *devname = "\0";        /* Device to download */
913         char    *dirname = NULL;        /* Directory path to objd files */
914         char    *objfile = NULL;        /* Command line object filename */
915         u_char  *ucode = NULL;          /* Pointer to microcode */
916         int     ucode_size = 0;         /* Length of microcode */
917         char    *sndfile = NULL;        /* Object filename to download */
918         char    filename[64];           /* Constructed object filename */
919         char    base[64];               /* sba200/sba200e/pca200e basename */
920         int     ext = 0;                /* 0 == bin 1 == objd */
921         struct stat sbuf;               /* Used to find if .bin or .objd */
922         extern char *optarg;
923
924         progname = (char *)basename(argv[0]);
925         comm_mode = strcmp ( progname, "fore_comm" ) == 0;
926
927         while ( ( c = getopt ( argc, argv, "i:d:f:berv" ) ) != -1 )
928             switch ( c ) {
929                 case 'b':
930                         binary++;
931                         break;
932                 case 'd':
933                         dirname = (char *)strdup ( optarg );
934                         break;
935                 case 'e':
936                         endian++;
937                         break;
938                 case 'i':
939                         devname = (char *)strdup ( optarg );
940                         break;
941                 case 'f':
942                         objfile = (char *)strdup ( optarg );
943                         break;
944                 case 'v':
945                         verbose++;
946                         break;
947                 case 'r':
948                         reset++;
949                         break;
950                 case '?':
951                         printf ( "usage: %s [-v] [-i intf] [-d dirname] [-f objfile]\n", argv[0] );
952                         exit ( 2 );
953             }
954         
955         /*
956          * Unbuffer stdout
957          */
958         setbuf ( stdout, NULL );
959                 
960         if ( ( fd = socket ( AF_ATM, SOCK_DGRAM, 0 ) ) < 0 )
961         {
962                 perror ( "Cannot create ATM socket" );
963                 exit ( 1 );
964         }
965         /*
966          * Over allocate memory for returned data. This allows
967          * space for IOCTL reply info as well as config info.
968          */
969         buf_len = 4 * sizeof(struct air_cfg_rsp);
970         if ( ( buf = (caddr_t)malloc(buf_len) ) == NULL )
971         {
972                 perror ( "Cannot allocate memory for reply" );
973                 exit ( 1 );
974         }
975         /*
976          * Fill in request paramaters
977          */
978         req.air_opcode = AIOCS_INF_CFG;
979         req.air_buf_addr = buf;
980         req.air_buf_len = buf_len;
981
982         /*
983          * Copy interface name into ioctl request
984          */
985         strcpy ( req.air_cfg_intf, devname );
986
987         /*
988          * Issue ioctl
989          */
990         if ( ( ioctl ( fd, AIOCINFO, (caddr_t)&req ) ) ) {
991                 perror ( "ioctl (AIOCSINFO)" );
992                 exit ( 1 );
993         }
994         /*
995          * Reset buffer pointer
996          */
997         req.air_buf_addr = buf;
998
999         /*
1000          * Close socket
1001          */
1002         close ( fd );
1003
1004         /*
1005          * Loop through all attached adapters
1006          */
1007         for (; req.air_buf_len >= sizeof(struct air_cfg_rsp); 
1008                         buf += sizeof(struct air_cfg_rsp),
1009                         req.air_buf_len -= sizeof(struct air_cfg_rsp)) {
1010
1011                 /*
1012                  * Point to vendor info
1013                  */
1014                 air = (struct air_cfg_rsp *)buf;
1015
1016                 if (air->acp_vendor == VENDOR_FORE )
1017                 {
1018                         /*
1019                          * Create /dev name
1020                          */
1021 #ifdef sun
1022                         sprintf ( bus_dev, DEV_NAME, air->acp_busslot );
1023 #else
1024                         sprintf ( bus_dev, DEV_NAME );
1025 #endif
1026
1027                         /*
1028                          * Setup signal handlers
1029                          */
1030                         signal ( SIGINT, SIG_IGN );
1031                         signal ( SIGQUIT, SIG_IGN );
1032                 
1033                         /*
1034                          * If comm_mode, setup terminal for single char I/O
1035                          */
1036                         if ( comm_mode ) {
1037                                 tty = open ( _PATH_TTY, O_RDWR );
1038                                 ioctl ( tty, TCGETA, &sgtty );
1039                                 sgtty.c_lflag &= ~( ICANON | ECHO );
1040                                 vmin = sgtty.c_cc[VMIN];
1041                                 vtime = sgtty.c_cc[VTIME];
1042                                 sgtty.c_cc[VMIN] = 0;
1043                                 sgtty.c_cc[VTIME] = 0;
1044                                 ioctl ( tty, TCSETA, &sgtty );
1045                         }
1046
1047                         /*
1048                          * Open bus for memory access
1049                          */
1050                         if ( ( fd = open ( bus_dev, O_RDWR ) ) < 0 )
1051                         {
1052                                 perror ( "open bus_dev" );
1053                                 fprintf(stderr, "%s download failed (%s)\n",
1054                                         air->acp_intf, bus_dev);
1055                                 continue;
1056                         }
1057
1058                         /*
1059                          * Map in the RAM memory to get access to the Uart
1060                          */
1061 #ifdef __FreeBSD__ /*XXX*/
1062                         ram = (u_char *) mmap(0, PCA200E_MMAP_SIZE,
1063 #else
1064                         ram = (u_char *) mmap(0, air->acp_ramsize,
1065 #endif
1066                                 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HASSEMAPHORE,
1067                                 fd, air->acp_ram);
1068                         if (ram == (u_char *)-1) {
1069                                 perror ( "mmap ram" );
1070                                 fprintf(stderr, "%s download failed\n",
1071                                         air->acp_intf);
1072                                 (void) close(fd);
1073                                 continue;
1074                         }
1075                         Mon = (Mon960 *)(ram + MON960_BASE);
1076                         Uart = (Mon960 *)&(Mon->mon_xmitmon);
1077
1078                         /*
1079                          * Determine endianess
1080                          */
1081                         switch ( Mon->mon_bstat ) {
1082                         case BOOT_COLDSTART:
1083                         case BOOT_MONREADY:
1084                         case BOOT_FAILTEST:
1085                         case BOOT_RUNNING:
1086                                 break;
1087
1088                         default:
1089                                 switch (ntohl(Mon->mon_bstat)) {
1090                                 case BOOT_COLDSTART:
1091                                 case BOOT_MONREADY:
1092                                 case BOOT_FAILTEST:
1093                                 case BOOT_RUNNING:
1094                                         endian++;
1095                                         break;
1096
1097                                 default:
1098                                         fprintf(stderr, "%s unknown status\n",
1099                                                 air->acp_intf);
1100                                         (void) close(fd);
1101                                         continue;
1102                                 }
1103                                 break;
1104                         }
1105
1106 #ifdef __FreeBSD__
1107                         if (reset) {
1108                                 u_int   *hcr = (u_int *)(ram + PCA200E_HCR_OFFSET);
1109                                 PCA200E_HCR_INIT(*hcr, PCA200E_RESET_BD);
1110                                 delay(10000);
1111                                 PCA200E_HCR_CLR(*hcr, PCA200E_RESET_BD);
1112                                 delay(10000);
1113                         }
1114 #endif
1115
1116                         if ( comm_mode ) {
1117                             static struct timeval timeout = { 0, 0 };
1118                             int esc_seen = 0;
1119
1120                             /*
1121                              * We want to talk with the i960 monitor
1122                              */
1123
1124                             /*
1125                              * Loop forever accepting characters
1126                              */
1127                             for ( ; ; ) {
1128                                 fd_set  fdr;
1129                                 int     ns;
1130
1131                                 /*
1132                                  * Check for data from the terminal
1133                                  */
1134                                 FD_ZERO ( &fdr );
1135                                 FD_SET ( fileno(stdin), &fdr );
1136
1137                                 if ( ( ns = select ( FD_SETSIZE, &fdr, NULL, NULL,
1138                                         &timeout ) ) < 0 ) {
1139                                                 perror ( "select" );
1140                                                 finish( -1 );
1141                                 }
1142
1143                                 if ( ns ) {
1144                                         int     c;
1145                                         int     nr;
1146
1147                                         nr = read ( fileno(stdin), &c, 1 );
1148                                         c &= 0xff;
1149                                         if ( !esc_seen ) {
1150                                             if ( c == 27 )
1151                                                 esc_seen++;
1152                                             else
1153                                                 xmit_byte ( c, 0 );
1154                                         } else {
1155                                             if ( c == 27 ) 
1156                                                 finish( -1 );
1157                                             else {
1158                                                 xmit_byte ( 27, 0 );
1159                                                 esc_seen = 0;
1160                                             }
1161                                             xmit_byte ( c, 0 );
1162                                         }
1163                                 }
1164
1165                                 /*
1166                                  * Check for data from the i960
1167                                  */
1168                                 if ( CP_READ(Uart->mon_xmithost) & UART_VALID ) {
1169                                         c = getbyte(0);
1170                                         putchar ( c );
1171                                 }
1172                                 if ( strcmp ( line, "Mon960" )  == 0 )
1173                                         autobaud();
1174
1175                             }
1176                         } else {
1177                             /*
1178                              * Make sure the driver is loaded and that the CP
1179                              * is ready for commands
1180                              */
1181                             if ( CP_READ(Mon->mon_bstat) == BOOT_RUNNING )
1182                             {
1183                                 fprintf ( stderr, 
1184                                 "%s is up and running - no download allowed.\n",
1185                                         air->acp_intf );
1186                                 (void) close(fd);
1187                                 continue;
1188                             }
1189                 
1190                             if ( CP_READ(Mon->mon_bstat) != BOOT_MONREADY )
1191                             {
1192                                 fprintf ( stderr, 
1193                                         "%s is not ready for downloading.\n", 
1194                                         air->acp_intf );
1195                                 (void) close(fd);
1196                                 continue;
1197                             }
1198                 
1199                             /*
1200                              * Indicate who we're downloading
1201                              */
1202                             if ( verbose )
1203                                 printf ( "Downloading code for %s\n",
1204                                         air->acp_intf );
1205
1206                             /*
1207                              * Look for the i960 monitor message. 
1208                              * We should see this after a board reset.
1209                              */
1210                             while ( strncmp ( line, "Mon960", 6 ) != 0 && 
1211                                 strncmp ( line, "=>", 2 ) != 0 )
1212                                 getline( verbose );     /* Verbose */
1213                 
1214                             /*
1215                              * Autobaud fakery
1216                              */
1217                             if ( strncmp ( line, "Mon960", 6 ) == 0 ) {
1218                                 xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 );
1219                                 delay ( 10000 );
1220                             }
1221
1222                             /*
1223                              * Keep reading until we get a command prompt
1224                              */
1225                             while ( strncmp ( line, "=>", 2 ) != 0 )
1226                                 getline( verbose );     /* Verbose */
1227
1228                             /*
1229                              * Choose the correct microcode file based on the
1230                              * adapter type the card claims to be.
1231                              */
1232                             switch ( air->acp_device )
1233                             {
1234                             case DEV_FORE_SBA200:
1235                                 sprintf ( base, "sba200" );
1236                                 break;
1237
1238                             case DEV_FORE_SBA200E:
1239                                 sprintf ( base, "sba200e" );
1240                                 break;
1241
1242                             case DEV_FORE_PCA200E:
1243                                 sprintf ( base, "pca200e" );
1244                                 break;
1245  
1246                             default:
1247                                 err = 1;
1248                                 fprintf(stderr, "Unknown adapter type: %d\n", 
1249                                         air->acp_device );
1250                             }
1251
1252                             sndfile = NULL;
1253
1254                             if ( objfile == NULL ) {
1255                                 switch ( air->acp_device ) {
1256                                 case DEV_FORE_SBA200:
1257                                 case DEV_FORE_SBA200E:
1258                                     sprintf ( filename, "%s.bin%d", base,
1259                                         air->acp_bustype );
1260                                     if ( stat ( filename, &sbuf ) == -1 ) {
1261                                         sprintf ( filename, "%s/%s.bin%d",
1262                                             dirname, base,
1263                                                 air->acp_bustype );
1264                                         if ( stat ( filename, &sbuf ) == -1 ) {
1265                                             ext = 1;
1266                                             sprintf ( filename, "%s.objd%d",
1267                                                 base, air->acp_bustype );
1268                                             if ( stat(filename, &sbuf) == -1 ) {
1269                                                 sprintf ( filename,
1270                                                     "%s/%s.objd%d", dirname,
1271                                                         base,
1272                                                             air->acp_bustype );
1273                                                 if ( stat ( filename, &sbuf ) != -1 )
1274                                                     sndfile = filename;
1275                                             } else
1276                                                 sndfile = filename;
1277                                         } else
1278                                             sndfile = filename;
1279                                     } else
1280                                         sndfile = filename;
1281                                     break;
1282                                 case DEV_FORE_PCA200E:
1283                                     /* Use compiled in microcode */
1284                                     ucode = pca200e_microcode;
1285                                     ucode_size = pca200e_microcode_size;
1286                                     break;
1287                                 default:
1288                                     break;
1289                                 }
1290                             } else
1291                                 sndfile = objfile;
1292
1293                             if ( ext && !binary )
1294                                 err = xmitfile ( sndfile );
1295                             else if (sndfile != NULL) 
1296                                 err = sendbinfile ( sndfile, ram );
1297                             else 
1298                                 err = loadmicrocode( ucode, ucode_size, ram );
1299
1300                             if ( err ) {
1301                                 fprintf(stderr, "%s download failed\n",
1302                                         air->acp_intf);
1303                                 (void) close(fd);
1304                                 continue;
1305                             }
1306
1307                             /*
1308                              * Download completed - wait around a while for
1309                              * the driver to initialize the adapter
1310                              */
1311                              aap = (Aali *)(ram + CP_READ(Mon->mon_appl));
1312                              for (i = 0; i < MAX_CHECK; i++, sleep(1)) {
1313                                 u_long  hb1, hb2, hb3;
1314
1315                                 hb3 = CP_READ(Mon->mon_bstat);
1316                                 if (hb3 != BOOT_RUNNING) {
1317                                         if (verbose)
1318                                                 printf("bstat %x\n", hb3);
1319                                         continue;
1320                                 }
1321
1322                                 hb1 = CP_READ(aap->aali_heartbeat);
1323                                 delay(1);
1324                                 hb2 = CP_READ(aap->aali_heartbeat);
1325                                 if (verbose)
1326                                         printf("hb %x %x\n", hb1, hb2);
1327                                 if (hb1 < hb2)
1328                                         break;
1329                              }
1330                         }
1331
1332                         close ( fd );
1333                 }
1334         }
1335
1336         /*
1337          * Exit
1338          */
1339         exit (0);
1340
1341 }
1342