unit RJScan; {******************************} { } { RJScan } { } { v1.1 } { } { } { by } { } { Roland Skinner } { } { Copyright (c) 1992 } { } { RJS Software } { } { Released to the public } { domain 1994. } { } {******************************} { Implements scanning ability for the DFI HS-3000 PLUS HANDY SCANNER or } { other 100% compatible hand-scanners (including certain GeniScans). } { NOTE - This unit may be overlayed. } { - This unit requires Turbo Pascal 6 (or above). } {$B-,D-,F+,G-,I-,L-,O+,R-,S-,V-,X-} {=============================================================================} interface {-----------------------------------------------------------------------------} const AnyResolution = 0; {-----------------------------------------------------------------------------} type ScanError = (scOK,scNoScanner,scInvalidResolution,scIncorrectResolution, scInvalidImageWidth); {-----------------------------------------------------------------------------} type ScanLineBufferProc = function(LineNumber : Integer) : Pointer; { NOTE - This function should return the address } { of the scan-buffer for the "LineNumber"th } { line. First line is number 0. } DisplayScannedLineProc = procedure(LineNumber : Integer); { NOTE - This procedure should display (if } { necessary) the "LineNumber"th line } { that was scanned in. First line is } { number 0. } StopScanningProc = function : Boolean; { NOTE - This function should return "False", unless } { some event has occurred which requires } { scanning to stop. } {-----------------------------------------------------------------------------} function ScanImage(DesiredResolution,MaxLinesToScan,BytesPerLine : Integer; ScanLineBuffer : ScanLineBufferProc; DisplayScannedLine : DisplayScannedLineProc; StopScanning : StopScanningProc) : ScanError; {- This function will scan an image with width 8*"BytesPerLine" and } { height "MaxLinesToScan". It is possible to specify the resolution at } { which to scan the image in "DesiredResolution" (100,200,300,400). } { If the resolution set on the scanner is different to that specified, } { then the "scIncorrectResolution" error will be returned. } { If "DesiredResolution" is "AnyResolution", then any resolution will } { be allowed. "scInvalidResolution" will be returned if a resolution } { other than 100,200,300,400 or "AnyResolution" is specified. } { "ScanLineBuffer", "DisplayScannedLine" and "StopScanning" are } { procedures/functions whose functions are discussed above. These must } { be FAR procedures/functions. } { If "BytesPerLine" is too large for the scanner-resolution, then } { "scInvalidImageWidth" will be returned. } { If scanner is not installed then "scNoScanner" is returned. } { If successful, then "scOK" will be returned. } { This function may not work with certain hand-scanners (if so, use } { "GenericScanImage"). } function GenericScanImage(MaxLinesToScan,BytesPerLine : Integer; ScanLineBuffer : ScanLineBufferProc; DisplayScannedLine : DisplayScannedLineProc; StopScanning : StopScanningProc) : ScanError; {- This function will scan an image in an analogous manner as } { "ScanImage". However, it does not do any checks for valid resolution } { or image-width. This is to allow compatibility for scanners which do } { not allow for scan-resolution selection. } { "scOK", "scNoScanner" and "scInvalidImageWidth" may be returned by } { this function. Refer to "ScanImage" for a discussion about these. } function ScannerIsInstalled : Boolean; {- Returns installed-status of scanner. } function ResolutionOfScanner : Integer; {- Returns the resolution set on the scanner. If scanner is not } { installed, then -1 will be returned. } { This function may not work with certain hand-scanners. } {=============================================================================} implementation {-----------------------------------------------------------------------------} const MaxBytesPerLine : Array[1..4] of Byte = (50,102,154,205); {-----------------------------------------------------------------------------} var ScannerInstalled : Boolean; ScannerResolution : Word; ScannerResolution100 : Byte; DMAChannel : Byte; DMAPageRegister : Word; DMACurAddrRegister : Word; DMACurWordCountRegister : Word; DMAClearSingleMaskBit : Byte; DMASetSingleMaskBit : Byte; DMAModeRegisterSetting : Byte; DMAWriteRequest : Byte; DMATerminalCountReached : Byte; {-----------------------------------------------------------------------------} procedure DetermineScannerResolution; assembler; var Data : Byte; asm xor ax,ax jmp @Start @ResSettings: db 21h,41h,51h,71h @Start: mov dx,27Bh mov cx,300 @1: in al,dx and al,10000000b jnz @1 @2: in al,dx and al,10000000b jz @2 loop @1 @3: in al,dx and al,10000000b jnz @3 @4: in al,dx and al,00100100b shr al,1 shr al,1 or ah,al shr al,1 shr al,1 or ah,al and ah,00000011b xor al,al xchg al,ah mov bl,4 sub bl,al mov al,bl push ax mov bx,OFFSET (@ResSettings-1) add bx,ax mov al,[cs:bx] mov dx,27Ah out dx,al mov Data,al pop ax mov ScannerResolution100,al mov cx,100 mul cx mov ScannerResolution,ax end; {-----------------------------------------------------------------------------} procedure DetermineScannerDMA; assembler; asm mov dx,27Bh in al,dx and al,00001010b cmp al,00001000b je @UseDMA1 cmp al,00000010b je @UseDMA3 jmp @NoDMA @UseDMA1: mov DMAChannel,1 mov DMAPageRegister, 83h mov DMACurAddrRegister, 02h mov DMACurWordCountRegister,03h mov DMAClearSingleMaskBit, 00000001b mov DMASetSingleMaskBit, 00000101b mov DMAModeRegisterSetting, 01000101b mov DMAWriteRequest, 00000001b mov DMATerminalCountReached,00000010b jmp @Exit @UseDMA3: mov DMAChannel,3 mov DMAPageRegister, 82h mov DMACurAddrRegister, 06h mov DMACurWordCountRegister,07h mov DMAClearSingleMaskBit, 00000011b mov DMASetSingleMaskBit, 00000111b mov DMAModeRegisterSetting, 01000111b mov DMAWriteRequest, 00000011b mov DMATerminalCountReached,00001000b jmp @Exit @NoDMA: mov DMAChannel,0 @Exit: end; {-----------------------------------------------------------------------------} procedure TurnScannerOn; assembler; asm mov dx,27Ah mov al,01h out dx,al end; {-----------------------------------------------------------------------------} procedure TurnScannerOff; assembler; asm mov dx,27Ah mov al,00h out dx,al end; {-----------------------------------------------------------------------------} procedure DMADelay; assembler; asm nop nop nop end; {-----------------------------------------------------------------------------} function DoScan(MaxLinesToScan,BytesPerLine : Integer; ScanLineBuffer : ScanLineBufferProc; DisplayScannedLine : DisplayScannedLineProc; StopScanning : StopScanningProc) : ScanError; var LinesScanned : Integer; ScanBuffer : Pointer; WidthToScan : Word absolute BytesPerLine; QuitScanning : Boolean; begin if (BytesPerLine>0) and (BytesPerLine<=MaxBytesPerLine[ScannerResolution100]) then begin LinesScanned := 0; QuitScanning := False; repeat ScanBuffer := ScanLineBuffer(LinesScanned); asm {-Disable DMA transfer } mov al,DMASetSingleMaskBit out 0Ah,al call DMADelay; mov al,DMAModeRegisterSetting out 0Bh,al call DMADelay {-Setup Buffer address } les di,ScanBuffer mov dx,es mov al,dh mov cl,4 shl dx,cl shr al,cl add dx,di adc al,0 mov cx,dx mov dx,DMAPageRegister out dx,al call DMADelay out 0Ch,al call DMADelay mov dx,DMACurAddrRegister mov al,cl out dx,al call DMADelay mov al,ch out dx,al call DMADelay {-Setup bytes to transfer } out 0Ch,al call DMADelay mov ax,WidthToScan dec ax mov dx,DMACurWordCountRegister out dx,al call DMADelay mov al,ah out dx,al {-Start DMA transfer } mov dx,27Bh out dx,al dec dx in al,dx { DX = 027Ah } mov al,DMAWriteRequest out 09h,al call DMADelay mov al,DMAClearSingleMaskBit out 0Ah,al end; {-Scan line } asm mov bl,DMATerminalCountReached @1: in al,08h and al,bl cmp al,bl je @2 push bx call StopScanning pop bx or al,al jz @1 mov QuitScanning,True @2: end; DisplayScannedLine(LinesScanned); Inc(LinesScanned); until (LinesScanned=MaxLinesToScan) or QuitScanning; DoScan := scOK; end else DoScan := scInvalidImageWidth; end; {-----------------------------------------------------------------------------} function ScanImage(DesiredResolution,MaxLinesToScan,BytesPerLine : Integer; ScanLineBuffer : ScanLineBufferProc; DisplayScannedLine : DisplayScannedLineProc; StopScanning : StopScanningProc) : ScanError; begin if ScannerInstalled then begin if (DesiredResolution=AnyResolution) or ((DesiredResolution div 100) in [1..4]) then begin TurnScannerOn; DetermineScannerResolution; if (DesiredResolution=AnyResolution) or (DesiredResolution=ScannerResolution) then ScanImage := DoScan(MaxLinesToScan,BytesPerLine, ScanLineBuffer,DisplayScannedLine,StopScanning) else ScanImage := scIncorrectResolution; TurnScannerOff; end else ScanImage := scInvalidResolution; end else ScanImage := scNoScanner; end; {-----------------------------------------------------------------------------} function GenericScanImage(MaxLinesToScan,BytesPerLine : Integer; ScanLineBuffer : ScanLineBufferProc; DisplayScannedLine : DisplayScannedLineProc; StopScanning : StopScanningProc) : ScanError; begin if ScannerInstalled then begin TurnScannerOn; ScannerResolution100 := 4; GenericScanImage := DoScan(MaxLinesToScan,BytesPerLine, ScanLineBuffer,DisplayScannedLine,StopScanning); TurnScannerOff; end else GenericScanImage := scNoScanner; end; {-----------------------------------------------------------------------------} procedure DetermineScannerPresence; begin TurnScannerOn; DetermineScannerDMA; TurnScannerOff; ScannerInstalled := (DMAChannel<>0); end; {-----------------------------------------------------------------------------} function ScannerIsInstalled : Boolean; begin ScannerIsInstalled := ScannerInstalled; end; {-----------------------------------------------------------------------------} function ResolutionOfScanner : Integer; begin if ScannerInstalled then begin TurnScannerOn; DetermineScannerResolution; TurnScannerOff; ResolutionOfScanner := ScannerResolution; end else ResolutionOfScanner := -1; end; {-----------------------------------------------------------------------------} begin DetermineScannerPresence; end. {=============================================================================}