[sane-devel] CanoScan 3200F: Some details of USB commands and a
request for assistance
Lauri Pirttiaho
lauri.pirttiaho at luukku.com
Wed Nov 16 19:59:47 UTC 2005
Hello,
Below are some details of the CanoScan 3200F USB commad set
and a request for assistance. As you can see from the command
set descriptions, they are a rather complex set and when
the protocol is added (the proper ordering of all the
commands, HW writes and Bulk writes) you see that the
this particular reverse engineering task (with absolutely
no assistance from either Canon of the chip maker ALi)
is a big task. That's why I can't promise anything about
the schedule of the back-end, more than tht at the moment
I am expecting to get something publishable by 2Q06.
In addition to the report in the beginning of this month,
I have now discovered a working AFE calibration and the
lamp controls and I am now working of the shading
calibration, which appears to be a harder piece of work.
Abstract
========
Description of the CanoScan 3200F command set findings so far
and a request of assistance in figuring out all parameters of
the mystery files written to address 0xdd00 (len 0x1e00 bytes)
prior to scanning.
The USB command set
===================
Below in tables 1 and 2 are descriptions of the dd00 file and the
USB commands the CanoScan 3200F understands. Note that these commands
alone are not enough to control the scanner but the control is a
mixture of commands and direct HW register writes an reads.
You may want to try to figure out, based on that information,
more about the control procedures. Below is a perl script to
process the SniffUSB logs to a form that you can easier scan
by eye. It also extracts the bulk transfers and images to
separate binary files and gives the file names in the textual
output.
Scanning set-up
===============
The scanner does scanning using a large number of settings.
- there is a set of HW register values written to addresses
ff40..ff58
- there is a set of values set by command vl=002b ix=0008
- there is a set of values to be witten to HW registers in the
file that is bulk-written to address dd00 length 1e00 (half
word address 6e80 length f00)
- there are the parameters of the scan command vl=0030.
Task for those willing to assist
================================
What I would you to do is to do as many scans as you have time to
and record the following using the perl script 2 below:
- the parameters of the scan command
- the parameters written to ff40..ff58
- the parameters of the last vl=002b ix=0008 command
- the speed ramps 1-3, data in offset 1c00, and data in offset 1d00.
Record also the parameters used when setting up the scan in GUI
and send me mail if you find something where the script 2 adds a
comment "Please report!"
The recommended procedure to get a snoop log is as follows:
1) Have the computer and scanner powered on and the scanner
plugged in. At that point the driver uploads the scanner firmware.
2) Unplug the scanner (don't switch the power off, though).
3) Start the imaging SW you are going to use to do TWAIN acquire.
4) Start the SniffUSB.exe (use the version 1.8 abailable from
http://benoit.papillault.free.fr/usbsnoop/).
5) Choose your 3200F from the list of USB devices and click install.
6) Plug in the scanner and observe that the sniffer log begins to grow
(if not, you have the wrong USB port instance selected).
7) Do the scan using the TWAIN control
8) Unplug the scanner (don't power it off, though - you can make a next scan
just by restarting at step 5 later)
9) Observe that the log stops growing.
10) Click uninstall.
11) Move the log to an empty working directory and rename it as you wish.
The log is originally in c:\WINDOWS as file usbsnoop.log.
12) repeat from 5 is you have time...
After that, process the file with the perl script given below
(Script 2) and save the output. (I recommend having Cygwin
(www.cygwin.com) and possibly ActivePerl (www.activestate.com) handy when doing the processings.)
With best regards,
Lauri Pirttiaho
Oulu
Finland
Table 1: Structure of the file written to dd00.
========================================================================
offs addr len Description
---- ---- ---- -----------
0000 DD00 0400 MSB
0400 E100 0400 LSB
- speed ramp 1 used for moving
0800 E500 0400 MSB
0C00 E900 0400 LSB
- speed ramp 2 used for positioning the head before scan
1000 ED00 0400 all 0, unused by firmware
1400 F100 0400 MSB
1800 F500 0400 LSB
- speed ramp 3 used for non-constant speed scanning
1C00 F900 003B 59 bytes of data going to HW registers:
00..1B -> FF00..FF1B
1C -> FF1D
1D..27 -> FF20..FF2A
28 -> FF37
29..2A -> FF1E..FF1F
2B -> FF1C
2C..35 -> FFF0..FFF9
36 -> FFFE
37..3A -> FFFA..FFFD
1C3B F93B 00C5 all 0, unused by firmware
1D00 FA00 0040 0/1 vector telling if 0xFFE0 high bit is on or off
- FFE0 = 0x83 or 0x03 (meaning???)
- the length is indicated at 1DC0/FAC0
- this and the next tables are used in vl=0030 and vl=0031 only
1D40 FA40 0040 F0/80 vector mirroring previous
- seems not to be used by the firmware
1D80 FA80 0040 0/1 vector telling is something happens in certain interrupt states
1DC0 FAC0 0001 number of states used in the three tables above
1DC1 FAC1 003F first count from 0 to cxFAC0-1 then 0
- seems to be unused by firmware
========================================================================
Table 2: The command parameters of the CanoScan 3200F.
========================================================================
device to host: (rt=c0 rq=04 except for one byte reads rq=0c)
---------------
vl=002a ix=0000 len=4
- read 4 bytes from addresses FB83..FB80
- bytes 0..1 form a word that is used as a line offset while scanning
- bytes 2..3 form a word that is used as a pixel offset while scanning
- corresponding write is vl=0029
vl=002c ix=n len=m
- read m bytes from address FB00+n
- ix=0000 seems to be some kind of state bit vector used by driver
- ix=0001 seems to be some kind of lamp warm-up timer
- ix=0006 is read but never written (AFAIK) and the firmware does not use
it either
- ix=0008 contains 10 bytes used in scanning (exact significance TBD)
- corresponding write vl=002b
vl=002d ix=0000 len=1
- key pressed indication (0=no key, 1=copy, 2=scan, 3=file, 4=e-mail)
- no corresponding write
vl=0040 ix=0000 len=1..6...
- status query
- byte 0: scanning state machine state
- byte 1: 0 or 0xFF (most likely the home detector)
- bytes 2-3: scan head position (line)
- byte 4: a status bit, possibly scan continue pending state
- byte 5: constant 0xAA (end marker)
- bytes 6...: 0
- no corresponding write
vl=0080 ix=0000 len=8
- read version string: "00000054"
- no corresponding write
vl=00e1 ix=n len=m
- read m bytes at addresses n..n+m-1
- corresponding write is vl=00e0
host to device: (rt=40 rq=04, there must be a terminating 0 which is ignored)
---------------
vl=0023 ix=0000 len=5
- move forward
- byte 0: bit 0 = 0: relative move, 1: absolute move
- bytes 1..2: distance to move (1200 lpi lines)
- byte 3: bit 1 = 0: full speed move, 1: half speed move
vl=0024 ix=0000 len=5
- move backward
- parameters as in vl=0023
vl=0029 ix=0000 len=5
- see vl=002a
vl=002b ix=n len=m+1
- see vl=002c
vl=0030 ix=0000 len=29
- scan (all parameters tentative!!!)
- bytes 0..1: time to spend scanning each CCD line (unit TBD)
(unless the ramp 3 in DD00-file is used)
- bytes 2..3: scanning resolution (any value may work but the driver
uses only 75/100/150/200/300/400/600/1200/2400)
- byte 4: a low bits affect the start position of the scan and
an offset for starting pixel (may have to do with CCD resolution)
- byte 5: goes to HW register FFE4
- byte 6: low 4 bits go to HW register FFE1
- byte 7: bit vector for modes
bit 0: vl=0029 bytes 2-3 added to starting pixel
bit 1: vl=0029 bytes 0-1 added to starting line
bit 2: may be unused
bit 3: initial movement 0: forward, 1: backwards
bit 4: 0: normal scan, 1: calibration mode?
bit 5: 0: constant speed scan, 1: scan in groups of lines
bit 6: 0: calibration mode?, 1: normal mode
bit 7: 0: continnue scan?, 1: new scan
- bytes 8..9: bulk transfer length for one scan line (in 16-bit words)
- bytes 10..11: starting pixel
- bytes 12..13: starting line
- bytes 14..15: scanning width
- byte 16: seems to be unused by the firmware
- byte 17: seems to be unused by the firmware
- byte 18: bit vector for move speed (x bits seem to be unused)
xxxx 00xx: move at normal speed
xxxx x1xx: move at half speed
xxxx 10xx: move at double speed
- byte 19: 0, seems to be unused by the firmware
- byte 20: seems to be unused by the firmware
- byte 21: seems to be unused by the firmware
- bytes 22..23: count of lines to output
- bytes 24..25: CCD resolution (300/600/1200)
- byte 26: bits 5:4 go to address FFB1 at some point, (which may be GOP)
- byte 27: 0, seems to be unused by the firmware
vl=0031 ix=0000 len=29
- scan one line (all parameters tentative!!!)
- bytes 0..1: time to spend scanning each CCD line (unit TBD)
- bytes 2..3: scanning resolution
- byte 4: 2 low bytes select an offset for starting pixel
- byte 5: goes to HW register FFE4
- byte 6: 0, seems to be unused by the firmware
- byte 7: 0, seems to be unused by the firmware
- bytes 8..9: bulk transfer length for one scan line (in 16-bit words)
- bytes 10..11: 0, seems to be unused by the firmware
- bytes 12..13: 0, seems to be unused by the firmware
- bytes 14..15: 0, seems to be unused by the firmware
- byte 16: 0, seems to be unused by the firmware
- byte 17: 0, seems to be unused by the firmware
- byte 18: 0, seems to be unused by the firmware
- byte 19: 0, seems to be unused by the firmware
- byte 20: 0, seems to be unused by the firmware
- byte 21: 0, seems to be unused by the firmware
- bytes 22..23: 0, seems to be unused by the firmware
- bytes 24..25: CCD resolution (300/600/1200)
- byte 26: seems to be unused by the firmware
- byte 27: 0, seems to be unused by the firmware
vl=0050 ix=0000 len=5
- set lamp watchdog times (time unit TBD)
- bytes 0..1: lamp watchdog first phase time
- bytes 2..3: lamp watchdog second phase time (WD disabled if 0xFFFF)
vl=0070 ix=0000 len=1
- reset scanning state machine (end of scan etc.)
- no params (just the terminating 0)
vl=0071 ix=0000 len=4
- move scan head home
- bytes 0..1: line to move to (usually 0)
- byte 2: bit 0: 0 = double speed, 1 = quad speed (TBD)
bit 1: 0 = high speed, 1 = normal speed (TBD)
vl=00b0 ix=0000 len=3
- this is not a firmware command but a boot ROM restart command
- the parameter may be the start address but that has not been tested
vl=00d0 ix=n len=3
- write a byte to AFE register n (see WM8196 data sheet for the regs)
- byte 0: ignored (0)
- byte 1: data to be written
vl=00e0 ix=n len=m+1
- write m bytes to addresses n..n+m-1
vl=00f0 ix=0000 len=5
- word address for the bulk transfer to/from DRAM
- the device seems to have 1M x 16 of DRAM
- bytes 0..2: the address
- byte 3: ignored
vl=00f3 ix=0000 len=4
- length of the bulk write (in 16-bit words) to DRAM
- bytes 0..1: the length
- byte 2: ignored
vl=00f4 ix=0000 len=4
- length of the bulk read (in 16-bit words) from DRAM
- bytes 0..1: the length
- byte 2: ignored
========================================================================
Script 1: Convert a SniffUSB log to a more readable form
========================================================================
#!perl
# usage: logfilt.pl < xxx.log > xxx.txt
$newimage = 1;
$image = 0;
$imagect = 0;
while ( <> ) {
if ( /^\[.*\] UsbSnoop/ ) {
next;
}
if ( /^\[.*\] Driver/ ) {
next;
}
if ( /^\[([0-9]+) ms\] +([<>]).*URB *([0-9]+)/ ) {
$t = $1;
$d = $2;
$u = $3;
$type = <>;
$type =~ /([A-Z_]+)/;
$type = $1;
# print "$d $type\n";
if ( $type eq "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER" ) {
$endp = <>;
$endp =~ /endpoint 0x000000(..)/;
$endp = $1;
$tbuflen = <>; #read one line off
$tbuflen = <>;
$tbuflen =~ /TransferBufferLength = (........)/;
$tbuflen = $1;
$dir = ( ( hex($endp) & 0x80 ) == 0 ) ? "o" : "i";
$dd = ( ( hex($endp) & 0x80 ) == 0 ) ? ">" : "<";
if ( $d ne $dd ) {
next;
}
if ( $newimage == 1 && $image == 1 ) {
$imagect++;
$newimage = 0;
}
if ( $image == 0 ) {
$fname = sprintf "%04d$dir.bin", $u;
}
else {
$fname = sprintf "image%02d.bin", $imagect;
}
printf "%06d/%06d:%04d B$dd ep=$endp tl=$tbuflen fn=\"$fname\"\n",
$t,0,$u;
open DF, ">>$fname";
binmode DF;
while ( <> ) {
if ( /TransferBufferMDL/ ) {
last;
}
}
while ( <> ) {
if ( ! /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
last;
}
@by = split / /,$1;
for ( @by ) {
if ( $_ ne "" ) {
print DF pack "C", hex;
}
}
}
close DF;
next;
}
if ( $d eq ">" ) {
$td = $t;
$urb = $u;
$tyd = $type;
if ( $type eq "URB_FUNCTION_ABORT_PIPE" ) {
$endp = <>;
$endp =~ /endpoint 0x000000(..)/;
$endp = $1;
}
elsif ( $type eq "URB_FUNCTION_RESET_PIPE" ) {
$endp = <>;
$endp =~ /endpoint 0x000000(..)/;
$endp = $1;
}
elsif ( $type eq "URB_FUNCTION_SELECT_CONFIGURATION" ) {
while ( <> ) {
if ( /iConfiguration *= 0x000000(..)/ ) {
$conf = $1;
last;
}
}
}
elsif ( $type eq "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE" ) {
while ( <> ) {
if ( /DescriptorType *= 0000(....) \(([^)]+)\)/ ) {
$dtype = $1;
$dname = $2;
last;
}
}
}
elsif ( $type eq "URB_FUNCTION_VENDOR_DEVICE" ) {
$vdata = "";
while ( <> ) {
if ( /TransferFlags *= 000000(..)/ ) {
$tf = $1;
}
elsif ( /TransferBufferLength = 0000(....)/ ) {
$tbl = $1;
}
elsif ( /RequestTypeReservedBits = 000000(..)/ ) {
$rt = $1
}
elsif ( /Request *= 000000(..)/ ) {
$rq = $1
}
elsif ( /Value *= 0000(....)/ ) {
$vl = $1;
}
elsif ( /Index *= 0000(....)/ ) {
$ix = $1;
last;
}
elsif ( /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
$vdata .= $1;
}
}
}
}
elsif ( $d eq "<" ) {
$tb = $t;
$tyu = $type;
if ( $type eq "URB_FUNCTION_ABORT_PIPE" ) {
printf "%06d/%06d:%04d AP ep=%s\n",$td,$tb,$urb,$endp;
}
elsif ( $type eq "URB_FUNCTION_RESET_PIPE" ) {
printf "%06d/%06d:%04d RP ep=%s\n",$td,$tb,$urb,$endp;
}
elsif ( $type eq "URB_FUNCTION_SELECT_CONFIGURATION" ) {
printf "%06d/%06d:%04d SC cf=%s\n",$td,$tb,$urb,$conf;
}
elsif ( $tyd eq "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE" ) {
$ddata = "";
while ( <> ) {
if ( /TransferBufferLength *= 0000(....)/ ) {
$tbl = $1;
}
elsif ( /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
$ddata .= $1;
}
elsif( /SetupPacket/ ) {
printf "%06d/%06d:%04d ", $td,$tb,$urb;
# print "GD $dtype ($dname) bl=$tbl ";
print "GD ty=$dtype bl=$tbl ";
print "dt=$ddata\n";
last;
}
}
}
elsif ( $tyd eq "URB_FUNCTION_VENDOR_DEVICE" ) {
while ( <> ) {
if ( /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
$vdata .= $1;
}
elsif( /SetupPacket/ ) {
printf "%06d/%06d:%04d ",$td,$tb,$urb;
if ( $tf == 0 ) {
print "> ";
}
else {
print "< ";
}
print "rt=$rt rq=$rq vl=$vl ix=$ix bl=$tbl ";
print "dt=$vdata\n";
$image = ( $vl eq '0030' ) ? 1 : 0;
$newimage = 1;
last;
}
}
}
}
}
}
========================================================================
Script 2: To scan a log and see if it contains something I have not seen
in the file downloaded to DD00.
========================================================================
#!perl
# usage logscan.pl < xxx.log >xxx.txt
use Digest::MD5 qw(md5_base64);
@std_ramp1 = (
"8LJxdy4V6RKXRtlkviFglg",
"APtIaw/82h1tB9XFk5n5Jg",
"WcwruerRuG8Ui54vwmkzIw"
);
@std_ramp2 = (
"5U7BUeddS1UpEM2ODnFVgA",
"9GMHFDSGWkTfjVqcQnG6Rw",
"9cCaeS09q/S4LB4JMJhEiQ",
"C18k4F+lZ1zLcBWYEX3Irw",
"JfYmr8w7BMcWzrUKwrR/yQ",
"JukXo5BaofZ976AriUQCCA",
"M2b0IZI3tuJovRgeDXlQVg",
"Px9w+60c7w4cdcuuqziQOQ",
"Z5Sp4oe3EWO1bkL9Y5CXRQ",
"eO0XgMoIk1byBw8GZwztCg",
"v9HdUc1/pTpwZBJOp6vzwg",
"xwT1WUC6VT+5vEdcMp1iRg"
);
@std_ramp3 = (
"+Gn2kRassyJEtMe+pBPi1Q",
"3Y816FYMWnrvpa6dju55eQ",
"LGgzV+BlgujrLjFmeY42MA",
"Pcbes62WLlABSQ+qTZcP6A",
"Pk4QkzXG7VgTzDLqf8kgbw",
"g/eLiZpVwaGNkrfzdg+ctg",
"j2DbvpZZpIq0u+Nh3PJnLA",
"kLjo3w99CINZrS2mB3pv9Q",
"n7VzSSEg8QQXkPYBPE3//Q"
);
@std_param = (
"Li3MpkNLNaCvb5eVc7yoog",
"LsGS5krzVXSRVMb9/GcyYA",
"yQlV6XKlSPRTOOA3F56SCQ"
);
@std_vects = (
"2PMYQDMZQPKEwBcmcQj5GA",
"86NTCVb5Y2YMfyEwGggqNg",
"F8EqgombcSthW8vWKJ04SA",
"Y1rKsY3W7YSxpKEurfymnQ",
"Zmzj4qmOVlcy0wnCdy0C5g",
"dSs5e0HGSILg1L67jHtZLA"
);
$newimage = 1;
$image = 0;
$imagect = 0;
$dd00 = 0;
while ( <> ) {
if ( /^\[.*\] UsbSnoop/ ) {
next;
}
if ( /^\[.*\] Driver/ ) {
next;
}
if ( /^\[([0-9]+) ms\] +([<>]).*URB *([0-9]+)/ ) {
$t = $1;
$d = $2;
$u = $3;
$type = <>;
$type =~ /([A-Z_]+)/;
$type = $1;
if ( $type eq "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER" ) {
$endp = <>;
$endp =~ /endpoint 0x000000(..)/;
$endp = $1;
$tbuflen = <>;
$tbuflen = <>;
$tbuflen =~ /TransferBufferLength = (........)/;
$tbuflen = $1;
$dir = ( ( hex($endp) & 0x80 ) == 0 ) ? "o" : "i";
$dd = ( ( hex($endp) & 0x80 ) == 0 ) ? ">" : "<";
if ( $d ne $dd ) {
next;
}
while ( <> ) {
if ( /TransferBufferMDL/ ) {
last;
}
}
while ( <> ) {
if ( ! /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
last;
}
@by = split / /,$1;
for ( @by ) {
if ( $_ ne "" ) {
if ( $dd00 ) {
$ddramp1 = "" if ( $ddptr == 0 );
$ddramp2 = "" if ( $ddptr == 0x800 );
$ddramp3 = "" if ( $ddptr == 0x1400 );
$ddparams = "" if ( $ddptr == 0x1c00 );
$ddvects = "" if ( $ddptr == 0x1d00 );
if ( $ddptr < 0x800 ) {
$ddramp1 .= $_;
}
elsif ( $ddptr < 0x1000 ) {
$ddramp2 .= $_;
}
elsif ( $ddptr < 0x1400 ) {
#ignore
}
elsif ( $ddptr < 0x1c00 ) {
$ddramp3 .= $_;
}
elsif ( $ddptr < 0x1c3b ) {
$ddparams .= $_;
}
elsif ( $ddptr < 0x1d00 ) {
#ignore
}
else {
$ddvects .= $_;
}
$ddptr++;
}
}
}
}
$dd00 = 0;
next;
}
if ( $d eq ">" ) {
$td = $t;
$urb = $u;
$tyd = $type;
if ( $type eq "URB_FUNCTION_VENDOR_DEVICE" ) {
$vdata = "";
while ( <> ) {
if ( /TransferFlags *= 000000(..)/ ) {
$tf = $1;
}
elsif ( /TransferBufferLength = 0000(....)/ ) {
$tbl = $1;
}
elsif ( /RequestTypeReservedBits = 000000(..)/ ) {
$rt = $1
}
elsif ( /Request *= 000000(..)/ ) {
$rq = $1
}
elsif ( /Value *= 0000(....)/ ) {
$vl = $1;
}
elsif ( /Index *= 0000(....)/ ) {
$ix = $1;
last;
}
elsif ( /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
$vdata .= $1;
}
}
}
}
elsif ( $d eq "<" ) {
$tb = $t;
$tyu = $type;
if ( $tyd eq "URB_FUNCTION_VENDOR_DEVICE" ) {
while ( <> ) {
if ( /^ *[[:xdigit:]]{8}:((?: ..){1,16})/ ) {
$vdata .= $1;
}
elsif( /SetupPacket/ ) {
if ( $vl eq '002b' && $ix eq '0008' ) {
$vl002bix0008 = $vdata;
}
elsif ( $vl eq '00f0' && $vdata eq ' 80 6e 00 00 00' ) {
$dd00 = 1;
$ddptr = 0;
}
elsif ( $vl eq '00e0' &&
( hex($ix) >= 0xff40 && hex($ix) <= 0xff58 ) ) {
$ff40[hex($ix)-0xff40] = hex( substr( $vdata, 1, 2 ) );
}
elsif ( $vl eq '0030' ) {
print "scan $vdata\n";
print " 2b/08 = $vl002bix0008\n";
print " ff40 =";
for ( $i = 0; $i <= 0x18; $i++ ) {
printf( " %02x", $ff40[$i] );
}
print "\n";
$ramp1md5 = md5_base64( $ddramp1 );
$ramp1known = 0;
for ( @std_ramp1 ) {
if ( $_ eq $ramp1md5 ) {
print " ramp1: $ramp1md5\n";
$ramp1known = 1;
last;
}
}
if ( ! $ramp1known ) {
print " ramp1: $ddramp1\n";
}
$ramp2md5 = md5_base64( $ddramp2 );
$ramp2known = 0;
for ( @std_ramp2 ) {
if ( $_ eq $ramp2md5 ) {
print " ramp2: $ramp2md5\n";
$ramp2known = 1;
last;
}
}
if ( ! $ramp2known ) {
print " ramp2: $ddramp2\n";
}
$ramp3md5 = md5_base64( $ddramp3 );
$ramp3known = 0;
for ( @std_ramp3 ) {
if ( $_ eq $ramp3md5 ) {
print " ramp3: $ramp3md5\n";
$ramp3known = 1;
last;
}
}
if ( ! $ramp3known ) {
print " ramp3: $ddramp3\n";
}
$parammd5 = md5_base64( $ddparams );
$paramknown = 0;
for ( @std_param ) {
if ( $_ eq $parammd5 ) {
print " param: $parammd5\n";
$paramknown = 1;
last;
}
}
if ( ! $paramknown ) {
print " param: $ddparams\n";
}
$vectsmd5 = md5_base64( $ddvects );
$vectsknown = 0;
for ( @std_vects ) {
if ( $_ eq $vectsmd5 ) {
print " vects: $vectsmd5\n";
$vectsknown = 1;
last;
}
}
if ( ! $vectsknown ) {
print " vects: $ddvects\n";
}
if ( ! $ramp1known ||
! $ramp2known ||
! $ramp3known ||
! $paramknown ||
! $vectsknown ) {
print "* Please report!\n";
}
}
last;
}
}
}
}
}
}
========================================================================
...................................................................
Luukku Plus paketilla pääset eroon tila- ja turvallisuusongelmista.
Hanki Luukku Plus ja helpotat elämääsi. http://www.mtv3.fi/luukku
More information about the sane-devel
mailing list