#!/usr/bin/perl

sub inquiry {
  @cmd = (0x12,0x00,0x00,0x00,120,0x00 );

  usb_cmd(@cmd);
  usb_read(8);
  $inq = usb_read(120);
  usb_read(8);
  
  $ivendor = substr($inq,8,8);
  $iproduct = substr($inq,16,16);
  $irev = substr($inq,32,4);
  $ifirmware = substr($inq,96,22);

  if($verbose) {
    print "Scanner Information (from scanner)\n";
    print "\tVendor:        $ivendor\n";
    print "\tVersion:       $irev\n";
    print "\tModel:         $iproduct\n";
    print "\tFirmware date: $ifirmware\n";
    print "\n";
  }
  
}

sub upload_firmware {
  $filename = shift;

  open FIRM, "<$filename" or die("Can't open $filename");
  undef $/;
  $firmware = <FIRM>;
  close FIRM;

  $info = substr($firmware, length($firmware)-128);
  $chip = substr($info,0,5);
  $vendor = substr($info,0x5,0x8);
  $model = substr($info,0xd,0x10);
  $version = substr($info,0x1d,5);
  $size = substr($info,0x22,0x2);
  $size = ord(substr($size,0,1)) + (ord(substr($size,1,1)) << 8);
  $fdate = substr($info,0x26,22);

  if( $vendor eq $ivendor &&
      $model eq $iproduct &&
      $fdate eq $ifirmware ) {
    if($verbose) {
      printf "Firmware is up to date.\n";
    }
    return 1;
  }
  
  if($verbose) {
    print "Firmware Information (from file)\n";
    print "\tChip:          $chip\n";
    print "\tVendor:        $vendor\n";
    print "\tVersion:       $version\n";
    print "\tModel:         $model\n";
    print "\tFirmware date: $fdate\n";
    print "\tSize:          $size\n";
    print "\n";
  }

  @cmd = (0x2a,0x00,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
  
  $cmd[7] = $size >> 8;
  $cmd[8] = $size & 0xff;

  usb_cmd(@cmd);
  usb_read(8);
  if($verbose) {
    print "Uploading new firmware...\n";
  }
  usb_write(substr($firmware,0,$size));  
  sleep(1);

  if($verbose) {
    print "Done!\n";
  }
  return 0;
}

sub print_binstr
{
  my $str = shift;
  for($i=0; $i<length($str); $i++) {
    printf("0x%02x ", ord(substr($str,$i,1)));
  }
  print "\n";
} 

sub usb_cmd {
  my $cmd="";
  my $c;
  foreach $c (@_) {
    $cmd .= chr($c);
  }
  syswrite(S,$cmd,length($cmd));
}

sub usb_write {
  $data = shift;
  syswrite(S,$data,length($data));
}

sub usb_read {
  my $length = shift;
  my $response="";
  sysread(S,$response,$length);
  return $response;
}

if($ARGV[0] eq "-v") {
  $verbose = 1;
  shift(@ARGV);
} 

if($ARGV[0] eq "-h" || $#ARGV < 0) {
  print 'AGFA Snapscan 1212U firmware uploader',"\n";
  print 'Written by Henrik Johansson (henrikjo@post.utfors.se) 2000-01-29',"\n";
  print 'THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!',"\n\n";

  print "Usage: agfafirm [-v] [-h] [DEVICE] FILE\n\n";
  print "DEVICE is the USB scanner device. If omitted, /dev/usbscanner will be used\n\n";
  print "FILE refers to the firmware file that comes with the Windows driver.\n";
  print "Example: SnapScan 1212U_2.bin.\n\n";
  print "Options:\n";
  print "\t-v\tverbose mode\n";
  print "\t-h\tthis helptext\n";
  exit 1;
}

if($#ARGV >= 1) {
  $device = shift(@ARGV);
} else {
  $device = "/dev/usbscanner";
}
  
open(S,"+>$device") or die("Can't open scanner device");
inquiry();
if(!upload_firmware($ARGV[0])) {
  inquiry();
}
close S; 

exit 0;
