#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/io.h>
#include <fcntl.h>

/* PCBRI Linux loader : V1.01 --BETA-- */
/* Copyright (C) 1995 -- Joel Katz -- Stimpson@Panix.COM */
/* All Rights Reserved */

static char *version=
"bri_load:v1.01 BETA - Joel Katz - Stimpson@Panix.COM\n";

void usage(char *n)
{
 fprintf(stdout, "Usage: %s net_port file_name\n\n",n);
 exit(1);
}

int ok2s(unsigned short net_port, int count, unsigned int wsf)
{
 if ( ((inw(net_port)-wsf)&65535) > (count+30) ) return 1;
 return 0;
}

int net_sync(int net_port, unsigned char test)
{
 int j=0;
 unsigned int nsr;
 nsr=0x0c3&inb(net_port-9);
 while((j++)<10)
 {
  if (((test==0)&&(nsr==0x42)) || ((test==1)&&(nsr!=0x42))) return 0;
  sleep(1);
 }
 return 1;
}

int main(int argc, char *argv[])
{
 char *port, *fnm;
 char buf[16384];
 int tmp,tmp2,in,tws;
 unsigned net_port;

 printf(version);
 if(argc!=3) usage(argv[0]);
 port=argv[1];
 fnm=argv[2];
 if(geteuid()) { fprintf(stdout,"Only root can load\n\n"); exit(4); }
 in=open(fnm,O_RDONLY);
 if(in==-1) { fprintf(stderr,"Cannot open %s\n\n",fnm); exit(2); }
 sscanf(port,"%x",&net_port);
 if(net_port<0x200||net_port>0x3d0)
  { fprintf(stdout,"Net port is out of range\n\n"); exit(3); }
 net_port+=0x10;
 if(ioperm(net_port-0x10,32,1))
  { fprintf(stdout,"Can't allocate net port\n\n"); exit(5); }
 tmp=0;
 outb(0x00,net_port+0x0e);
 while(tmp<4 && ((inb(net_port-9)&0xc3)!=0x42) )
  { printf("Resetting BRI\n"); outb(0xff,net_port+0x0e); sleep(2); tmp++; }
 if(tmp>3) { fprintf(stderr,"Cannot reset PCBRI\n\n"); exit(6); }
 sleep(5);
 if(net_sync(net_port,0))
  { fprintf(stderr,"PCBRI won't sync before load\n\n"); exit(7); }
 read(in,buf,20); /* FIXME -- might not always be 10 words */
 sscanf(buf+5,"%d",&tmp);
 printf("Loading %d words.\n",tmp);
 outw(10,net_port);
 outsw(net_port,buf,10);
 tws=11;
 while (tmp=read(in,buf,2048))
 {
  if(tmp==-1) { fprintf(stderr,"\nIO Error reading file\n\n"); exit(8); }
  if(tmp&1) { fprintf(stderr,"\nOdd error (haha)\n\n"); exit(9); }
  tmp2=0;
  tmp>>=1;
  while(!ok2s(net_port,tmp,tws))
  {
   tmp2++;
   usleep(tmp2*10000);
   if(tmp2>40) { fprintf(stderr,"\nFIFO won't empty.n\n"); exit(10); }
  }
  outsw(net_port,buf,tmp);
  tws+=tmp;
 }
 printf("Load Complete\n");
 return 0;
}
