;VCA32.ASM
;*****************************************************************
; OS/2 2.0 VCA device driver
;
; Supports both the NTSC and PAL versions of the adapter.
;
;
;   Device driver functions
;   -----------------------
;   OPEN
;     Open the device when ready to use VCA adapter.
;
;   CLOSE
;     Close device when no longer being used.
;
;   IOCTL
;     Category 140
;
;       The following functions (code 7x) are for use by 32-bit OS/2
;       applications/subsystems:
;
;       code 61h - Save   Setup Info
;
;       code 62h - Retore Setup Info
;
;       code 6Eh - Set Video Rectangle Size\Crop\Scale Info (Capture Image Size)
;
;       code 6Eh - Capture Image into a RAM buffercale Info (Capture Image Size)
;
;       code 70h - Return 32-bit flat address to video buffer and
;                  number of 16K banks.
;
;       code 71h - Select VRAM bank number
;
;       code 72h - Select live/capture mode
;
;       code 73h - Select live mode (freeze)
;
;       code 74h - Single frame capture
;                  Enter live/capture mode, poll capture-in-progress
;                  until two fields are captured, the return to live mode.
;
;       code 75h - Set video adjustments
;                  Brightness, saturation, hue, contrast
;
;       code 76h - Set Time (frames per second) based Image Capture (streaming)
;
;       code 77h - Single frame capture asynchronous   ***** Not Supported (removed) ****
;                  Enter live/capture mode and enable the end-of-field
;                  interrupt.  The interrupt handler returns the card
;                  to live mode and disables the interrupt.
;
;                  The intent of this function is that it will be invoked
;                  immediately after data is copied out of the capture
;                  buffer so that video digitizing will be asynchronous,
;                  and the new image will be complete by the time the
;                  copy code is invoked again.  This should avoid contention
;                  between the digitizer and the copy/convert code.
;
;       code 90h - Set Register 12                     ***** Not Supported (removed) ****
;
;
;*****************************************************************
title VCA32.ASM OS/2 2.0 Device driver for the Video Capture Adapter
page 55,132

.386p
;******************************************************************************
;  I N C L U D E S
;******************************************************************************
INCL_DOSMISC    EQU     1
INCL_DOSERRORS  EQU     1
INCL_TYPES      EQU     1
INCL_DEF        EQU     1

.xlist
include devsym.inc
include devhlp.inc
include basemaca.inc
include basedef.inc
include VIDIN.inc
include vididc.inc         ;struc for IDC stream instance
include vidvci.inc         ; Struc of IOCTLS request packets
include os2medef.inc
include meerror.inc
include ssm.inc
include shdd.inc
.list

EXTRN   DOS32FLATDS:ABS             ; 32 bit r/w FLAT selector
EXTRN   _VCACOPYBUF:FAR             ; Copy image from VCA H/W to buffer
EXTRN   _VCACOPYBUF2:FAR            ; Copy image from VCA H/W multibank to buffer
EXTRN   IDC_ENTRY:FAR               ; IDC Entry Point
EXTRN   TIMEINTRPT:FAR              ; Common Interrupt processing for streaming


INIT_TEXT   SEGMENT WORD PUBLIC 'INITCODE' USE16
        EXTRN   INIT:FAR
INIT_TEXT   ENDS


LBegin  macro len
        push    ebp
        mov     ebp,esp
        sub     esp,len
        endm
LEnd    macro
        mov     esp,ebp
        pop     ebp
        endm


DATA     SEGMENT word public 'DATA' USE16 ; All code and data segments must be named
                                    ; and declared public
 PUBLIC FlatSel, GetI2RAM
 PUBLIC selector1, named, device_hlp
 PUBLIC Ginfo_Seg, Ginfo_offset, lsw_phys_add, msw_phys_add, device_id, MC_MACHINE
 PUBLIC pages, IOBASE, IORANGE
 PUBLIC Intr_level, Intr_channel, DAC_Default
 PUBLIC hue, saturation, contrast, REG12
 PUBLIC INT_HAND, TotalBytesinBank, SETBANKNUM
 PUBLIC usr_Y_Height, usr_X_Width, usr_ScaleFactor, usr_FPS, usr_X_Left, usr_Y_Top
 PUBLIC usr_DY_Height, usr_DX_Width, usr_DX_Left, usr_DY_Top
 PUBLIC Lin_Addr
 PUBLIC d_brightness, d_hue, d_saturation, d_contrast
 PUBLIC VCA_opens

CAPTURE_DEVICE    equ  140          ;IOCTL User defined catagory for image capture device
devlev_1          equ  0000000010000000B ;Bits 7-9 - DOS 5.0
dev_char_dev      equ  1000000000000000B ;Bit 15-Device is a character device
dev_30            equ  0000100000000000B ;Bit 11-Accepts open/close
dev_IDC           equ  0100000000000000B ;Bit 14-Accepts IDC command


;------------------ DEVICE DRIVER HEADER ---------------------------------------
Dev_Header        equ  $
ptr_to_nxt_hdr    dd   -1           ;Indicates loadable device driver
device_attr       dw   devlev_1 + dev_char_dev + dev_30 + dev_IDC
offst             dw   _TEXT:strategy  ;Offset to the strategy routine
idc_offset        dw   _TEXT:IDC_entry ;Offset to IDC Entry Point routine
named             db   'VIDVCIx$ '  ;Name of the device
reserved_words    dw   4 dup (0)    ;Reserved words
;------------------ END OF DEVICE DRIVER HEADER --------------------------------

;------------------- DEVICE IDs OF SUPPORTED DEVICES --------------------------
VCA_ID         equ  704Eh    ;NTSC version of VCA adapter
VCA_PAL        equ  70CEh    ;PAL version of  VCA adapter

;***************************************
;* IocTab - Table of Generic IOCTALs   *
;***************************************
        EVEN
        PUBLIC  IocTab
IocTab LABEL WORD
        DW     30H                       ;--- Number of Entries in this Table
        DW     CODE_60H            ;60  ; Init Parms
        DW     CODE_61H            ;61  ; Save current Setup Info
        DW     CODE_62H            ;62  ; Restore Setup Info
        DW     CODE_unk            ;63  ; Unknow Function (command not supported)
        DW     CODE_unk            ;64  ; Unknow Function (command not supported)
        DW     CODE_unk            ;65  ; Unknow Function (command not supported)
        DW     CODE_unk            ;66  ; Unknow Function (command not supported)
        DW     CODE_unk            ;67  ; Unknow Function (command not supported)
        DW     CODE_unk            ;68  ; Unknow Function (command not supported)
        DW     CODE_unk            ;69  ; Unknow Function (command not supported)
        DW     CODE_unk            ;6A  ; Unknow Function (command not supported)
        DW     CODE_6BH            ;6B  ; Set Capture Image Size
        DW     CODE_6CH            ;6C  ; Capture Image and Scale to RAM buffer
        DW     CODE_6DH            ;6D  ; Get Device Info
        DW     CODE_6EH            ;6E  ; Set Capture Image Size
        DW     CODE_6FH            ;6F  ; Capture image into RAM buffer
        DW     CODE_unk            ;70  ; (Not Supported) Get addressability to VRAM
        DW     CODE_71H            ;71  ; Select VRAM Bank Number
        DW     CODE_72H            ;72  ; Select Live capture mode
        DW     CODE_unk            ;73  ; Unknow Function (command not supported)
        DW     CODE_74H            ;74  ; Select Live Mode then Freeze
        DW     CODE_75H            ;75  ; Video Adjustments
        DW     CODE_76H            ;76  ; Set Time Based Capture
        DW     CODE_unk            ;77  ; Unknow Function (command not supported)
        DW     CODE_unk            ;78  ; Unknow Function (command not supported)
        DW     CODE_unk            ;79  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7A  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7B  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7C  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7D  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7E  ; Unknow Function (command not supported)
        DW     CODE_unk            ;7F  ; Unknow Function (command not supported)
        DW     CODE_unk            ;80  ; Unknow Function (command not supported)
        DW     CODE_unk            ;81  ; Unknow Function (command not supported)
        DW     CODE_unk            ;82  ; Unknow Function (command not supported)
        DW     CODE_unk            ;83  ; Unknow Function (command not supported)
        DW     CODE_unk            ;84  ; Unknow Function (command not supported)
        DW     CODE_unk            ;85  ; Unknow Function (command not supported)
        DW     CODE_unk            ;86  ; Unknow Function (command not supported)
        DW     CODE_unk            ;87  ; Unknow Function (command not supported)
        DW     CODE_unk            ;88  ; Unknow Function (command not supported)
        DW     CODE_unk            ;89  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8A  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8B  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8C  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8D  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8E  ; Unknow Function (command not supported)
        DW     CODE_unk            ;8F  ; Unknow Function (command not supported)
        DW     CODE_unk            ;90  ; Unknow Function (command not supported)

IntrI2RAM      dd      0
getI2RAM       dd      0
eye_catcher    db      '         VCA DEVICE DRIVER DATA AREA  '
count_74s      dd      0
               dw      0
               dw      0
;............................. Buffer for tace Data ....................................
Trace_ptr      dd      0
trace_start    equ     $
               dw     300 dup(0)
Trace_end      equ     $
               dw     16  dup(0)
               db     '!TRACE DATA END!'
;............................. Buffer for tace Data ....................................

MC_MACHINE     db      1    ; 1 = Micro Channel Machine,  0 = NON-Micro Channel Machine
;GDTsel         dw      0    ; GDT Selector
FlatSel        dw      0    ; Flat Selector

done              equ   0100h           ; code for DONE
error_s           equ   8000h           ; status code for error
general_failure   equ   000ch           ; General failure error code
unknown_command   equ   0003h           ; Unknown command error code
not_supported     equ     21h  ;-223    ; This capture device is not supported
not_available     equ     22h  ;-222    ; This capture device is not available
cat_not_supported equ     23h  ;-221    ; IOCTL catagory not supported
fun_not_supported equ     24h  ;-220    ; IOCTL function not supported
REG8_Intr_Active     equ  00000010b     ; Reg 8 interrupt is active

;-------------------------------------------------------------------------------
;Structure of an INIT request packet
;-------------------------------------------------------------------------------
IP       equ   es:[bx]          ;Request packet
INITpkt  struc
         db      ?
         db      ?
_Cmd     db      ?                      ; Command code
_Stat    dw      ?                      ; Status word
         dd      ?
         dd      ?
         db      ?
_DHptr   dd      ?                      ; dev help pointer
         dd      ?
         db      ?
INITpkt  ends
;-------------------------------------------------------------------------------
;Structure of a General IOCTL request packet
;-------------------------------------------------------------------------------
GIO     equ   es:[bx]
GIOpkt  struc
         db      ?
         db      ?
         db      ?                      ; Command code
         dw      ?                      ; Status word
         dd      ?
         dd      ?
_cat     db      ?                      ; category
_code    db      ?                      ; function code
_Parm    dd      ?                      ; address of parms
_Data    dd      ?                      ; address of data (see icdevice.anc)
GIOpkt  ends

;-------------------------------------------------------------------------------
; General IOCTL output data structures
;-------------------------------------------------------------------------------
GIX     equ   es:[bx]

;-------------------------------------------------------------------------------
; Defaults for the Device   (must match info in VIDVCI.H/INC  ... don't change ... add to end only)
;-------------------------------------------------------------------------------
Defaults          equ $
D_Length          dd   Defaults_End - Defaults            ; Length of Structure/Data
                       ;123456789012345678901234567890
prod_info         db   'IBM Video Capture Adapter     '   ; Name of the device
Manufacture_info  db   'IBM                           '   ; Owner of The PDD
Version_info      db   '0.2       '                       ; Version Number
Img_format_info   dd   1                                  ; RGB
BitsPerPEL_info   dw   16                                 ; Bit Per PEL
Overlay           dw   0                                  ; Overlay Device
I_brightness      dd   d_brightness
I_hue             dd   d_hue
I_saturation      dd   d_saturation
I_contrast        dd   d_contrast
I_Sharpness       dd   -1                                ; Not Supported
unused1           dd   0                                 ; Unused
S_X_Left          dd   0                                 ; Default Source Info
S_Y_Top           dd   0
S_Y_Height        dd   480
S_X_Width         dd   640
D_X_Left          dd   0                                 ; Default Destination
D_Y_Top           dd   0
D_Y_Height        dd   480/4
D_X_Width         dd   640/4
D_ScaleFactor     dd   4
S_X_MAX           dd   640                               ; Max X for Source
S_Y_MAX           dd   480                               ; Max Y for Source
D_X_MAX           dd   640                               ; Max X for Dest
D_Y_MAX           dd   480                               ; Max Y for Dest
O_X_MAX           dd    0            ; Max X for Overlay ; Not supported
O_Y_MAX           dd    0            ; Max Y for Overlay ; Not supported
VideoInputs       dw    1                                ; Not supported
CanRestore        dw    0                                ; Not supported
CanStretch        dw    0                                ; Not supported
CanDistort        dw    0                                ; Not supported
HasVolume         dw    0                                ; Not supported
HasBalance        dw    0                                ; Not supported
CanScale          dw    1                                ; Can Scale Down
CanStream         dw    1                                ; Can Stream
Instance_ID       dd    0            ; Returned Instance ID for stream
Defaults_End     equ $
;-------------------------------------------------------------------------------
; Misc data area used by driver
;-------------------------------------------------------------------------------
device_hlp    dd   ?         ; Holds address of the DevHlp functions
VCA_opens     dd   0         ; open count
buffer_phys   dd   0         ; physical address of buffer
lin_addr      dd   0         ; 32 bit linear address
aper_size     dd   0         ; VRAM buffer aperature size in bytes
Timer_on        dw   0       ; Is time based capture turned on (1=True)
parm_es         dw   0       ; parameter packet Selector
parm_bx         dw   0       ; parameter packet Offset
Ginfo_Seg       dw   0       ; Global Info Segment
Ginfo_offset    dw   0       ; Global Info Offset
LastImg         dd   0       ; Time Last Real time capture was done
Tic_Intr        dd   0       ; Count of interrupts taken to capture image
Skipped         dd   0       ; Number of frames skipped on this interrupt
round           dd   0       ; Number of times tic_next rounded up on this interrupt
Card_Buff       dd   0       ; Address of Image buffer on Capture Card
Intr_level      db   0       ; Interrupt level number
Intr_channel    db   0       ; Interrupt level bits from POS3 (used in reg 5)
Reg8_Trace      db   0       ; Trace Data from Reg 8
Trace_Stime     dw   0       ; Start of trace
Total_skipped   dw   0       ; Total Number of frames skipped on all interrupt

; The following values align with the structure returned by the v1.02 driver

device_id  dw      0      ;704e for NTSC version, 70Ce for PAL  version
                          ;. 0 if neither installed
                          ;/*Each microchannel slot is checked beginning at slot 1
                          ;until one of the two adapters are found or all
                          ;slots are checked.
iobase     dw      0      ;/*I/O address base FROM SYSTEM*/
iorange    dw      0      ;/*Range of I/O addresses from base FROM SYSTEM*/
pages      dw      0      ;/*Number of valid pages FROM SYSTEM*/
res1       dw      0      ;
os         dw      0      ;/*operating system address mode FROM SYSTEM (9999=DOS)*/
lsw_phys_add dw    0      ;/*Real 32 bit address LSW FROM SYSTEM*/
msw_phys_add dw    0      ;/*Real 32 bit address MSW FROM SYSTEM*/
selector1  dw      0      ;/*Selector of real address FROM SYSTEM. (Same as segment address for DOS) */
reg6         db    0      ;/*Host memory access,eeprom CS,SK,DI  FROM SYSTEM
reg8         db    0      ;/*status,EEPROM DO (read only)  FROM SYSTEM
reg12        db    0      ;/*screen capture position  FROM SYSTEM
reg14        db    0      ;/*signals and format  FROM SYSTEM
                          ;/*value SENT used to determine EEPROM values below
reg15        db    0      ;/*mode  FROM SYSTEM

TotalBytesinBank dd 0     ;Total number of bytes in a bank on the VCA card

Field_info  equ 11100000B
Field_2     equ 00100000B
;
; The adapter has EEPROM that contains factory calibrated values
; for NTSC ( or PAL), Y/C, and RGB modes.
; Using the values in the EEPROM will calibrate the adapter per mode.
; The values returned in the following fields are the EEPROM values based
; on the field defined in _reg14:
;
;   0xxxxxx0=NTSC,1xxxxxx0=Y/C,1xxxxxxx=RGB
;
; The driver code that reads the following EEPROM values normalizes the
; values from 0(dark) to 1023(light)
;
dac_default  equ   $
dark_blue    dw    0      ;EEPROM stored value for  dark blue
dark_green   dw    0      ;EEPROM stored value for dark green
dark_red     dw    0      ;EEPROM stored value for dark red
light_blue   dw    0      ;EEPROM stored value
light_green  dw    0      ;EEPROM stored value
light_red    dw    0      ;EEPROM stored value
hue          dw    0      ;EEPROM stored value
saturation   dw    0      ;EEPROM stored value
contrast     dw    0      ;EEPROM stored value
reg8chk      dw    0      ;Register 8 check
res3         db    0      ;


; Corresponding values to above, except current values

dac_current  equ   $
c_dk_blue    dw    0
c_dk_green   dw    0
c_dk_red     dw    0
c_lt_blue    dw    0
c_lt_green   dw    0
c_lt_red     dw    0
c_hue        dw    0
c_sat        dw    0
c_cont       dw    0

;
; Default Video Adjustments
;
d_brightness  equ  128
d_hue         equ  128
d_saturation  equ  128
d_contrast    equ  128
;
; Defaults as set by Init
ID_brightness       dd   D_brightness
ID_hue              dd   D_hue
ID_saturation       dd   D_saturation
ID_Contrast         dd   D_contrast

; Video adjustment settings as seen by the user
;
usr_brightness  dd   128   ; 1=min, 255=max, 128=norm, 0=no change, -1=default
usr_hue         dd   128   ; 1=min, 255=max, 128=neutral, 0=no change, -1=default
usr_saturation  dd   128   ; 1=min, 255=max, 128=norm, 0=no change, -1=default
usr_contrast    dd   128   ; 1=min, 255=max, 128=norm, 0=no change, -1=default

; Image capture Rate as set by the user thru IOCTL 67 "Set Capture Rate"
;
usr_FPS         dw   10         ; Frames Per Second (FPS) image capture rate


; Image capture Info as set by the user thru IOCTL 6E "Set Capture Image Size"
;
usr_X_Left      dd   0          ; Offset in X from the left of the image
usr_Y_Top       dd   0          ; Offset in Y from the top of the image
usr_Y_Height    dd   480        ; Height of image
usr_X_Width     dd   640        ; Width  of image
usr_ScaleFactor dd   4          ; Scale image down by this factor
usr_DX_Left     dd   0          ; Offset in X from the left of the image
usr_DY_Top      dd   0          ; Offset in Y from the top of the image
usr_DY_Height   dd   120        ; Height of image
usr_DX_Width    dd   160        ; Width  of image

mindacval    equ  100h
maxdacval    equ  3ffh
minhueval    equ  0
maxhueval    equ  3ffh
minsatval    equ  0
maxsatval    equ  3ffh
mincontval   equ  0
maxcontval   equ  3ffh

  Public OI_LIST, OI_CURR
OI_LIST         dd  0           ; List of Open Instance
OI_CURR         dd  0           ; Current Open Instance


OC_FN_OFFSET  equ  13           ; Offset to File Handle in OPEN and Close IOCTL
GN_FN_OFFSET  equ  23           ; Offset to File Handle in Generic IOCTL
DATA ENDS
;*******************************************************************************

subttl Strategy Routine
page
_TEXT     SEGMENT  word public 'CODE' USE16  ;Define code segment
          assume cs:_TEXT,ds:DATA,es:NOTHING

;-------------------------------------------------------------------------------
; Far Procedure STRATEGY gets the request packet and based on its command code
; branches to the appropriate subroutine. Upon return from the subroutine,
; the request is signalled serviced with or without error.
;-------------------------------------------------------------------------------
STRATEGY PROC  FAR
                                         ; IP (ES:BX) = request packet address
;   int 3; <<---------------<<<<<
         and   IP._Stat,error_s + unknown_command
         mov   al,byte ptr IP._Cmd      ; Command code
         cmp   al,0                     ; Is it INIT call ?
         jne   strat13                  ; no,
         mov   IP._Stat,0
         call  INIT                     ; yes,
         cmp   ax,0                     ; Init's Return Code non-zero= failure
         jnz   stratGF                  ; Did init Fail?
         jmp   strat8                   ; go to common exit
strat13: cmp   al,13                    ; is it OPEN call ?
         jne   strat14                  ; no
         call  OPEN                     ; yes
         jmp   strat8                   ; go to common exit
strat14: cmp   al,14                    ; is it CLOSE call ?
         jne   strat16                  ; no
         call  CLOSE                    ; yes
         jmp   strat8                   ; go to common exit
strat16: cmp   al,16                    ; is it IOCTL call ?
         jne   strat7                   ; no, go to unknown command
         mov   IP._Stat,0
         call  IOCTL                    ; do IOCTL processing
         jmp   strat8                   ;
stratGF: or    IP._Stat,error_s + general_failure
         jmp   strat8                   ;
strat7:  or    IP._Stat,error_s + unknown_command
strat8:  or    IP._Stat,done            ; set complete flag
         ret
STRATEGY ENDP



subttl Strategy Routine
page
;-------------------------------------------------------------------------------
; Procedure for handling General IOCTLs for device
;-------------------------------------------------------------------------------
IOCTL    PROC  NEAR
;        int 3  ;<<----------------------<<<<<<<<<<<<<<<<
         push  es                       ; save request packet pointer
         push  bx                       ;
         cmp   GIO._cat,CAPTURE_DEVICE  ; Check for category  (same as IP address)
         je    IOCTL_LOOKUP             ;
;-------------------------------------------------
         mov   ax,cat_not_supported
         jmp   gout

;TABLE LOOKUP for IOCTL hander Routine
IOCTL_LOOKUP:
;        int 3  ;<<----------------------<<<<<<<<<<<<<<<
        mov     cx,[IocTab]             ; Get # of functions in table into CX
        xor     eax,eax
        mov     al,GIO._code            ; al =  function
        sub     al,60h                  ; Base Entry Which Entry in the table
        jb      chk_n                   ; function out of range (too small)
        cmp     al,cl                   ; Function in range? (too big)
        ja      chk_n                   ; function out of range
        shl     eax,1                   ; word offset for dispatch table
        call    IocTab[eax+2]           ; Call the function
        jmp     gout                    ; Ioctl done


chk_n:
         mov   ax,fun_not_supported
gout:
         pop   bx                       ; restore request packet pointer
         pop   es                       ;
         cmp   ax,0                     ; Has any error occured?
         jz    goutok                   ; NO, then jump
         or    ax,error_s               ; YES, then turn on  error flag
         or    IP._Stat,ax              ; put in status field
goutok:
         RET
IOCTL    ENDP

CODE_unk PROC NEAR
;-------------------- Unknow Function ------------------------
         mov   ax,fun_not_supported
         ret
CODE_unk ENDP



subttl Interrupt Routine
;-------------------------------------------------------------------------------
; Interrupt routine
;
; Handles End-of-Frame interrupts from the VCA Card
;
;  Uses system millisecond counter to judge when it's time to capture the next image
;  Then when the application has specified more frames per second than the CPU can
;  support the sytem timer will get locked out and time will appear to stand still, this
;  will cause this code to stop captureing images utill the system timer can get back in
;  to update the time to the correct value. At this point we may have skipped some frames
;  but because the system is now correct we can calculate how many we skipped.
;
;-------------------------------------------------------------------------------
INT_HAND PROC  FAR
        cli
        mov   dx,iobase
        add   dx,8                   ; Register 8 on the card
        in    al,dx                  ; Read Status Register (reg8)
        mov   Reg8_Trace,al          ; Trace Data from Reg 8
        and   al,REG8_Intr_Active    ; Is an interrupt pending for our cardb
        jz    Intr_not_ours          ; No interrupt pending (not us)

Intr_is_ours:
; INTERRUPT IS OURS
;   * Clear interrupt on VCA card
;   * Issue EOI
;   * Read Image form Hardware (if it's the correct time)
;   * Clear Carry Flag to show our card caused the Interrupt


        ; Clear the active Interrupt from the VCA card
        mov   dx,iobase
        add   dx,8                   ; Register 8 on the card
        out   dx,al                  ; Write to REG8 clear Intr_active

        ; Issue EOI
        mov     al, Intr_Level
        mov     dl, DevHlp_EOI
        call  device_hlp               ;
        sti

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>  IF (Correct Time)  Read Image from the VCA Card  and Stream >>>>>>>>>>>>>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        CALL  TIMEINTRPT


int_exit:
        clc                          ; Clear Carry Flag to show it
                                     ; was our Interrupt
        jmp     INTR_DONE

;
; Interrupt not caused by our card (exit with Carry Flag set without doing
; a DevHelp EOI
Intr_not_ours:
        stc                          ; tell caller - not our Interrupt

INTR_DONE:
         ret                         ;

INT_HAND ENDP

CODE_60H PROC NEAR
;-------------- Init Parms (60H) -------------------------------------------

        mov   ax,word ptr GIO._Data+2 ; get address of data area
        mov   bx,word ptr GIO._Data   ;
        mov   es,ax                   ; es:bx-->data area

        mov   eax,GIX.IN_ulBrightness ; get the brightness value to set
        mov   usr_brightness,eax      ; save current user value
        mov   ID_brightness,eax       ; Save Init Default
        mov   I_brightness,eax        ; Save Init Default

; now do the hue
        mov   eax,GIX.IN_ulHue        ; get the hue value to set
        mov   usr_hue,eax             ; save current user value
        mov   ID_hue,eax              ; Save Init Default
        mov   I_hue,eax               ; Save Init Default

; now do the saturation
        mov   eax,GIX.IN_ulSaturation ; get the sat value from parms
        mov   usr_saturation,eax      ; save current user value
        mov   ID_saturation,eax       ; Save Init Default
        mov   I_saturation,eax        ; Save Init Default

; now do the Contrast
        mov   eax,GIX.IN_ulContrast   ; get the Contrast value from parms
        mov   usr_Contrast,eax        ; save current user value
        mov   ID_Contrast,eax         ; Save Init Default
        mov   I_Contrast,eax          ; Save Init Default

; now do the contrast     >>>---> not supported by H/W <---<<<


; Set the control register
        mov   dx,iobase
        add   dx,14                   ; DX = reg 14 (Control)
        mov   al,GIX.IN_bControl      ; get the Control reg Info
                                      ; bit 7  0 = Normal Decoding
                                      ;        1 = C to decode from Red Input
                                      ;            Y to decode from Green Input
                                      ; bit 6  0 = 6 6 4 Format
                                      ;        1 = 5 6 5 Format (always)
                                      ; bit 5  1 = Display Cursor
                                      ;        0 = Do not Diplay Cursor
                                      ; bit 4  1 = Display Enabled
                                      ;        0 = Display Disabled
                                      ; bit 3  0 = Gen Lock off
                                      ;        1 = Gen Lock on
                                      ; bit 2  1 = Output Sync to Analog Green
                                      ; bit 1    = unused
                                      ; bit 0  0 = NTSC/PAL or Y/C input
                                      ;        1 = RGB input
        out   dx,al                   ;

; Set the Capture Posistion Register
        mov   dx,iobase
        add   dx,12                   ; DX = reg 12 (capture position Control)
        mov   al,GIX.IN_bCappos       ; Capture Position Info
        out   dx,al                   ;

        mov   reg12,al                ; Save Reg 12 Info

        sub   ax,ax                   ; indicate no error
        ret
CODE_60H ENDP


CODE_61H PROC NEAR
;-------------------- Save Setup Info ------------------------

         ; Save all instance information
         PUSHFD
         CLI
         mov   cx,GIO.GN_FN_OFFSET     ; System File Number
         CALL  far ptr FIND_OI         ; Is it In the List?
         CMP   EAX,0                   ; Not in List
         JNE   Save_Fail               ; Error - not found in the list

         mov   OI_CURR,0               ; Mark as NO current Instance
         ;......... do save suff ......
         ;......... Save Current Setting
         xor   ax,ax                   ; RC = Success
         jmp   save_exit               ; all done

save_fail:
         mov   ax,-1

save_exit:
         POPFD
         RET
CODE_61H ENDP

CODE_62H PROC NEAR
;-------------------- Restore Setup Info ------------------------

         PUSHFD
         CLI
         ; Restore all instance information
         mov   cx,GIO.GN_FN_OFFSET     ; System File Number
         CALL  far ptr FIND_OI         ; Is it In the List?
         CMP   EAX,0                   ; Not in List
         JNE   Restore_Fail            ; Error - not found in the list

         mov   OI_CURR,eax             ; Mark as current Instance
         ;......... do restore suff ......
         ;......... Restore Setting ......
         xor   ax,ax                   ; RC = Success
         jmp   restore_exit            ; all done

restore_fail:
         mov   ax,-1

restore_exit:
         POPFD
         ret
CODE_62H ENDP

CODE_6DH PROC NEAR
;-------------------- Get Default Info (6DH) --------------------------

       ; Load up Default info for caller
       mov   dx,GIO.GN_FN_OFFSET     ; System File Number
       mov   ax,word ptr GIO._Data+2  ; get address of data area
       mov   bx,word ptr GIO._Data    ;
       mov   es,ax                    ; es:bx-->data area

       mov   ecx,GIX.DI_Length
       cmp   ecx,0
       je    too_Small
       cmp   ecx,D_Length
       jb    too_small
       mov   si,offset Defaults
       mov   di,bx

copy_defaults:
       REP  MOVS byte ptr es:[di], byte ptr ds:[si] ; copy the Dafault Info

       ; Find  Stream Instance
       mov   di,bx                    ; Start of Parm List
       mov   es:[di].DI_ulFileNum,-1; Assume Invalid Instance
       mov   fs,flatsel
       mov   cx,dx                    ; System File Number
       call  far ptr FIND_OI
       cmp   eax,0                    ; 0 = Invalid Stream Handle
       je    CODE_6DH_DONE            ; Instance is not active
       xor   ebx,ebx
       mov   bx,fs:[eax].OI_FILENUM   ; File Number for this OPEN
       mov   es:[di].DI_ulFileNum,EBX ; File Number for the Caller

       sub   ax,ax                    ; indicate no error
       jmp   CODE_6DH_DONE

Too_Small:
       mov   ax,1                                     ; !!! Too Small

CODE_6DH_DONE:
       ret
CODE_6DH ENDP

CODE_6BH PROC NEAR
;-------------------- SET Source and Destination Image Info (6BH) ------------

       ; Save Parms away for use later by Image Capture Routines
       mov   ax,word ptr GIO._Data+2  ; get address of data area
       mov   bx,word ptr GIO._Data    ;
       mov   es,ax                    ; es:bx-->data area

       ; Save Video Acquisition Source window Info
       mov   eax,GIX.CR_Source_X_Left
       mov   usr_X_Left,eax
       mov   eax,GIX.CR_Source_Y_Top
       mov   usr_Y_Top,eax
       mov   eax,GIX.CR_Source_Y_Height
       mov   usr_Y_Height,eax
       mov   eax,GIX.CR_Source_X_Width
       mov   usr_X_Width,eax

       ; Save Video Distination/Display window Info
       mov   eax,GIX.CR_Dest_X_Left
       mov   usr_DX_Left,eax
       mov   eax,GIX.CR_Dest_Y_Top
       mov   usr_DY_Top,eax
       mov   eax,GIX.CR_Dest_Y_Height
       mov   usr_DY_Height,eax
       mov   eax,GIX.CR_Dest_X_Width
       mov   usr_DX_Width,eax

       sub   ax,ax                    ; indicate no error
       ret
CODE_6BH ENDP

CODE_6EH PROC NEAR
;-------------------- SET CAPTURE IMAGE SIZE (6EH) --------------------------

       ; Save Parms away for use later by Image Capture Routines
       mov   ax,word ptr GIO._Data+2  ; get address of data area
       mov   bx,word ptr GIO._Data    ;
       mov   es,ax                    ; es:bx-->data area

       mov   eax,GIX.CS_X_Left
       mov   usr_X_Left,eax

       mov   eax,GIX.CS_Y_Top
       mov   usr_Y_Top,eax

       mov   eax,GIX.CS_Y_Height
       mov   usr_Y_Height,eax

       mov   eax,GIX.CS_X_Width
       mov   usr_X_Width,eax

       mov   eax,GIX.CS_ScaleFactor
       mov   usr_ScaleFactor,eax


       sub   ax,ax                    ; indicate no error
       ret
CODE_6EH ENDP

CODE_6CH PROC NEAR
;-------------------- CAPTURE IMAGE AND SCALE RAM BUFFER (6CH) ------------------
      Buf_Lock          EQU     12h                  ; Linear Buffer Lock Address
      G_Buff_Addr       EQU     16h                  ; Global Buffer Address
      ScaleDown         EQU     20h                  ; Scale Down Image by
      Input_Parms       EQU     24h                  ; Input Parms Address

       inc  [GetI2RAM]                               ; Count Number of Calls

       LBegin 24h
       mov   ax,word ptr GIO._Data+2  ; get address of data area
       mov   bx,word ptr GIO._Data    ;
       mov   es,ax                    ; es:bx-->data area
       mov   [ebp-Input_parms],bx     ; Save ptr to input parms

       ;Check to make sure Source and Destination Rectangles are valid
       ;Partial Check below just to get scale info
       ;**** caller of this function ->M U S T<- always make sure ****
       ;**** Source and Destination info are <= maxium size       ****
       ;**** Destination * N = Source where N is a Whole Number   ****
       ;**** Destination Height and Width / 8 is a Whole Number   ****
       mov     eax,GIX.GIS_Source_Y_Height; Y_Height for Source Rect
       mov     ecx,GIX.GIS_Dest_Y_Height  ; Y_Height for Dect   Rect
       cmp     ecx,0                      ; Must be non-Zero
       je      Invalid_rectl_6C           ; not supported
       xor     edx,edx                    ; Zero for Divide
       div     cx                         ; Source/Dest scale in Y
       and     eax,0FFFFh                 ; Zero high part of eax
       mov     [ebp-ScaleDown],eax        ; Save Quotient\Scale Factor
       cmp     dx,0                       ; Must be even Multiple
       jne     Invalid_rectl_6C           ; not supported
       mov     eax,GIX.GIS_Source_X_Width ; X_Width for Source Rect
       mov     ecx,GIX.GIS_Dest_X_Width   ; X_Width for Dect   Rect
       cmp     ecx,0                      ; Must be non-Zero
       je      Invalid_rectl_6C           ; not supported
       xor     edx,edx                    ; Zero for Divide
       div     cx                         ; Source/Dest scale in Y
       cmp     dx,0                       ; Must be even Multiple
       jne     Invalid_rectl_6C           ; not supported
       cmp     [ebp-ScaleDown],ax         ; Scale in X and Y must be the same
       jne     Invalid_rectl_6C           ; not supported

       ;Lock Down user buffer so ring 0 can access it to copy image into
       lea     esi,[ebp-Buf_Lock]                  ; esi:Lock Handle Location
       mov     ax,ss                               ; Stack Segment
       mov     ecx,GIX.GIS_Capture_Buf_Len         ; Lenght of image buffer
       mov     ebx,GIX.GIS_Capture_Buf_Ptr         ; Buffer to put image into
       call    LockMem
       jc      Invalid_Buff_6C                     ; Exit With Error

       mov     [ebp-G_Buff_addr],eax               ; Save Global Copy Buffer Address

       mov     ax,FlatSel               ; load up flat selector for VMAlloced memory
       mov     fs,ax

       PUSHFD
;       CLI                               ; Block Interrupts

       ; Put Parameters on the stack for the Call to the Copy Image buffer routines
       mov       bx,[ebp-Input_parms]        ; Get ptr to input parms
       ; Is Scanline Double required (Only 1 fields captured and Scale = 1)
       xor       eax,eax                     ; Assume Double not required
       mov       edx,[ebp-ScaleDown]         ; Scale
       mov       cl,reg12
       and       cl,field_info               ; Bot Fields captured?
       jz        Double_info                 ; Both fields were captured
       cmp       edx,1                       ; Scale = 1?
       jne       Double_info                 ; Scale not equal to 1
       mov       eax,1                       ; Double of scanlines required
double_info:
       push      eax                         ; Double
       push      edx                         ; Scale Factor
       mov       eax,GIX.GIS_Source_Y_Height ; Y_Height
       push      eax
       mov       eax,GIX.GIS_Source_X_Width  ; X_Width
       push      eax
       mov       eax,GIX.GIS_Source_Y_Top    ; Y_Top
       push      eax
       mov       eax,GIX.GIS_Source_X_Left   ; X_Left
       push      eax
       mov       eax,[ebp-G_Buff_addr]       ; Destination Buffer
       push      eax


       mov       eax,[Lin_addr]             ; Source Buffer
       push      eax                        ; Source Buffer


       ;****  Which Copy Scale Routine should we use

       ; is this VCA setup with a full aperture
       mov       ax,pages               ; Number of pages in a bank
       cmp       ax,40                  ; 40 pages in a bank is Full Aperture
       jne       multibankcopy_6C       ; NOT full aperture

singlebankcopy_6C:                       ; Image in a single bank
       call      _VCACopyBuf             ; R E A D    I N    T H E    I M A G E
       jmp       bankcopydone_6C

multibankcopy_6C:                        ; Image in multiple banks
       call      _VCACopyBuf2            ; R E A D    I N    T H E    I M A G E

bankcopydone_6C:
       add       esp,4*8                 ; Remove the parameters from the stack
       POPFD                             ; Enable Interrupts (back to old value)

       ;UnLock users image copy buffer
       lea     esi,[ebp-Buf_Lock]            ; esi:Lock Handle Location
       mov     ax,ss                         ; Stack Segment
       mov     ebx,[ebp-G_Buff_addr]         ; Get Global Copy Buffer Address
       call    UnLockMem
       jc      Invalid_Buff_6C               ; Exit With Error

       mov     ax,VCAERR_SUCCESS             ; indicate no error
       jmp     GetISDone

Invalid_Buff_6C:                             ; Invalid Buffer
       mov     ax,VCAERR_INVALID_BUFFER
       jmp     GetISDone

Invalid_rectl_6C:                               ; Invalid Rectangle
       mov     ax,VCAERR_INVALID_RECT
       jmp     GetISDone

GetISDone:
         lend
         ret
CODE_6CH ENDP


CODE_6FH PROC NEAR
;-------------------- CAPTURE IMAGE TO RAM BUFFER (6FH) --------------------------
      Buf_Lock          EQU     12h                  ; Linear Buffer Lock Address
      G_Buff_Addr       EQU     16h                  ; Global Buffer Address

       inc  [GetI2RAM]                               ; Count Number of Calls

       LBegin 20h
       mov   ax,word ptr GIO._Data+2  ; get address of data area
       mov   bx,word ptr GIO._Data    ;
       mov   es,ax                    ; es:bx-->data area

 ;!!!!!!   ; "freeze" The Image

       ;Lock Down user buffer so ring 0 can access it to copy image into
       lea     esi,[ebp-Buf_Lock]                  ; esi:Lock Handle Location
       mov     ax,ss                               ; Stack Segment
       mov     ecx,GIX.GI_Capture_Buf_Len        ; Lenght of image buffer
       mov     ebx,GIX.GI_Capture_Buf_Ptr        ; Buffer to put image into
       call    LockMem
       jc      GetIDone                            ; Exit With Error in EAX  (invalid Buffer)
       mov     [ebp-G_Buff_addr],eax               ; Save Global Copy Buffer Address

       mov     ax,FlatSel               ; load up flat selector for VMAlloced memory
       mov     fs,ax

       ; Put Parameters on the stack for the Call to the Copy Image buffer routines
       mov       eax,usr_ScaleFactor     ; Scale
       push      eax

       mov       eax,usr_Y_Height        ; Y_Height
       push      eax

       mov       eax,usr_X_Width         ; X_Width
       push      eax

       mov       eax,usr_Y_Top           ; Y_Top
       push      eax

       mov       eax,usr_X_Left          ; X_Left
       push      eax

       mov       eax,[ebp-G_Buff_addr]   ; Destination Buffer
       push      eax

       mov       eax,[Lin_addr]          ; Source Buffer
       push      eax

       PUSHFD
;       CLI                               ; Block Interrupts *********************************


       ; is this VCA setup with a full aperture
       mov       ax,pages               ; Number of pages in a bank
       cmp       ax,40                  ; 40 pages in a bank is Full Aperture
       jne       multibankcopy          ; NOT full aperture

singlebankcopy:                          ; Image in a single bank
       call      _VCACopyBuf             ; R E A D    I N    T H E    I M A G E
       jmp       bankcopydone

multibankcopy:                           ; Image in multiple banks
       call      _VCACopyBuf2            ; R E A D    I N    T H E    I M A G E

bankcopydone:
       add       esp,4*7                 ; Remove the parameters from the stack
       POPFD                             ; Restore Interrupt ?*******************************

;!!!! ; "Unfreeze" the image

       ;UnLock users image copy buffer
       lea     esi,[ebp-Buf_Lock]            ; esi:Lock Handle Location
       mov     ax,ss                         ; Stack Segment
       mov     ebx,[ebp-G_Buff_addr]         ; Get Global Copy Buffer Address
       call    UnLockMem
       jc      GetIDone                      ; Exit With Error in EAX  (invalid Buffer)

       sub   ax,ax                          ; indicate no error

GetIDone:
         lend
         ret
CODE_6FH ENDP


;CODE_70H PROC NEAR
;;-------------------- GET BUFFER ADDRESSING (70H) --------------------------
;         mov   ax,word ptr GIO._Data+2  ; get address of data area
;         mov   bx,word ptr GIO._Data    ;
;         mov   es,ax                    ; es:bx-->data area
;         mov   eax,lin_addr             ; get linear address
;         mov   GIX.BA_buf_addr,eax      ; .
;         mov   eax,aper_size            ; return the aperature size
;         mov   GIX.BA_buf_len,eax       ; .
;
;         sub   eax,eax                  ; get number of banks from aper size
;         mov   dx,pages                 ; .
;         xor   dh,dh                    ; DL = number of pages
;         mov   al,40                    ; DL = divisor
;         div   dl                       ; AL = quotient, AH = remainder
;         xor   ah,ah                    ; clear remainder (should be zero)
;         mov   GIX.BA_buf_banks,eax     ; return number of banks
;
;         sub   ax,ax                    ; indicate no error
;         ret
;CODE_70H ENDP

CODE_71H PROC NEAR
;-------------------- SELECT VRAM BANK NUMBER (71H) ------------------------
         mov   ax,word ptr GIO._Data+2  ; get address of data area
         mov   bx,word ptr GIO._Data    ;
         mov   es,ax                    ; es:bx-->data area
         mov   ecx,GIX.SB_bank_num      ; get bank number to select

         call  SETBANKNUM               ; Set the Bank Number

         sub   ax,ax                   ; indicate no error
         ret
CODE_71H ENDP


CODE_72H PROC NEAR
;-------------------- SET LIVE/CAPTURE MODE (72H) --------------------------

;
;  Make sure lock is achieved
;
         mov   ecx,0FFFFH       ; number of times to retry lock
chklock72:
         mov   ebx,1000h
delay_some:
         dec   ebx
         jnz   delay_some

         add   dx,8             ; status register
         in    al,dx            ; read the status register
         and   al,04H           ; see if lock is active
         jnz   setlcmode

         mov   dx,iobase        ; try to re-establish sync (see tech ref p3-36)
         add   dx,14            ; control register
         in    al,dx            ; read the control register
         and   al,0F7H          ; turn off genlock
         out   dx,al            ; .
         or    al,08H           ; turn genlock back on
         out   dx,al            ; .
         dec   ecx
         jnz   chklock72        ; go see if it worked
;         mov   ax,1             ; indicate lock not achieved
;         jmp   setlcerr         ; .

setlcmode:
;
;        Set the capture control register (tech ref p.3-31)
;
;        Defaults:
;           Capture type is interlaced, 262.5 lines/field, both fields
;           sync lock position = 12 (per tech ref)
;
;       mov   dx,iobase
;       add   dx,12                   ; DX = reg 12 (capture control)
;       mov   al,0CH                  ; bits 765 = 000, 5 lsb's = 12
;       out   dx,al                   ;
;
; Set live/capture mode
;
         mov   dx,iobase
         add   dx,15                   ; DX = reg 15 (Mode control)
         mov   al,06H                  ; bits 2-0 = 1 1 0 = live/capture mode
         out   dx,al                   ;

;Wait for a few field times to let Image capture sync up
         mov   dx,iobase
         add   dx,8                    ; status register
         mov   bx,2                    ; Wait >>>---> N frame times for image sync
one_more_frame:
         mov   ah,10
         mov   cx,0
even_field:
         mov   cx,0
wait_field0:
         in    al,dx                   ; read the status register
         and   al,21H                  ; retain field number and Vertical Sync
         cmp   al,20H                  ; v.b. active and field = 0 ?
         jz    odd_field               ; Now Wait For Field 1
         loop  wait_field0             ; keep looping until CIP rises
         dec   ah
         jnz   wait_field0            ; outer loop (buy more time!!!)
;        mov   ax,2                   ; indicate vertical blanking not signalled
         mov   ax,0
         jmp   setlcerr               ; .
odd_field:
         mov   ah,10
         mov   cx,0
wait_field1:
         in    al,dx                   ; read the status register
         and   al,21H                  ; retain field number and Vertical Sync
         cmp   al,21H                  ; v.b. active and field = 1 ?
         jz    wait_frame_done         ; Got New Field
         loop  wait_field1             ; keep looping until CIP rises
         dec   ah
         jnz   wait_field1            ; outer loop (buy more time!!!)
;        mov   ax,2                   ; indicate vertical blanking not signalled
         mov   ax,0
         jmp   setlcerr               ; .
Wait_frame_Done:
         dec   bx                     ; Wait N frame times
         jnz   one_more_frame


         sub   ax,ax                   ; indicate no error
setlcerr:
         ret
CODE_72H ENDP

CODE_73H PROC NEAR
;-------------------- SET LIVE MODE (73H) ---------------------------------

         mov   dx,iobase               ; get I/O address
         add   dx,15                   ; DX = reg 15 (Mode control)
         mov   al,02H                  ; bits 2-0 = 0 1 0 = live mode
         out   dx,al                   ;
         sub   ax,ax                   ; indicate no error
         ret
CODE_73H ENDP


CODE_74H PROC NEAR
;-------------------- SINGLE FRAME CAPTURE (74H) --------------------------

;
;        Set the capture control register (tech ref p.3-31)
;
;        Defaults:
;           Capture type is interlaced, 262.5 lines/field, both fields
;           sync lock position = 12 (per tech ref)
;
;        mov   dx,iobase
;        add   dx,12                   ; DX = reg 12 (capture control)
;        mov   al,0CH                  ; bits 765 = 000, 5 lsb's = 12
;        out   dx,al                   ;

         mov   bx,iobase               ; get I/O address in BX
;
;  Make sure lock is achieved
;
;         mov   cx,1000          ; number of times to retry lock
;chklock:
;         mov   dx,bx
;         add   dx,8             ; status register
;         in    al,dx            ; read the status register
;         and   al,04H           ; see if lock is active
;         jnz   lockok

;         mov   dx,bx            ; try to re-establish sync (see tech ref p3-36)
;         add   dx,14            ; control register
;         in    al,dx            ; read the control register
;         and   al,0F7H          ; turn off genlock
;         out   dx,al            ; .
;         or    al,08H           ; turn genlock back on
;         out   dx,al            ; .
;         loop  chklock          ; go see if it worked
;         mov   ax,1             ; indicate lock not achieved
;         jmp   caperr           ; .
;
; Busy loop waiting for vertical blanking on first field
;
lockok:
         mov   dx,bx
         add   dx,8                    ; status register
         mov   ah,100
         mov   cx,0
fldwait:
         in    al,dx                   ; read the status register
         and   al,21H                  ; retain field number and vert blank
         cmp   al,20H                  ; v.b. active and field = 0 ?
         jz    lcmode                  ; jump out when true
         loop  fldwait                 ; keep looping until CIP rises
         dec   ah
         jnz   fldwait                 ; outer loop (buy more time!!!)
         mov   ax,2             ; indicate vertical blanking not signalled
         jmp   caperr           ; .
;
; Set live/capture mode
;
lcmode:
         mov   dx,bx
         add   dx,15                   ; DX = reg 15 (Mode control)
         mov   al,06H                  ; bits 2-0 = 1 1 0 = live/capture mode
         out   dx,al                   ;
;
; Busy loop waiting for capture-in-progress (tech ref p. 3-35)
;
         mov   dx,bx
         add   dx,8                    ; status register
         mov   cx,0
capwait:
         in    al,dx                   ; read the status register
         and   al,40H                  ; check CIP
         jnz   caprise                 ; jump out when CIP rises
         loop  capwait                 ; keep looping until CIP rises
         mov   ax,3             ; indicate capture start not successful
         jmp   caperr           ; .
;
; capture has started, now enter live mode
;
caprise:
         mov   dx,bx
         add   dx,15                   ; DX = reg 15 (Mode control)
         mov   al,02H                  ; bits 2-0 = 0 1 0 = live mode
         out   dx,al                   ;
;
; now wait for capture-in-progress to go low
;
         mov   dx,bx
         add   dx,8                    ; status register
         mov   cx,0
ciplowwait:
         in    al,dx                   ; read the status register
         and   al,40H                  ; check CIP
         jz    ciplow                  ; jump out when CIP goes low
         loop  ciplowwait              ; keep looping until CIP goes low
         mov   ax,4             ; indicate capture start not successful
         jmp   caperr           ; .

ciplow:
         sub   ax,ax                   ; indicate no error
caperr:
         ret
CODE_74H ENDP

CODE_75H PROC NEAR
;-------------- SET/QUERY VIDEO ADJUSTMENTS (75H) --------------------------
        mov   ax,word ptr GIO._Data+2  ; get address of data area
        mov   bx,word ptr GIO._Data    ;
        mov   es,ax                    ; es:bx-->data area

        mov   eax,GIX.SV_set_brightness ; get the brightness value to set
        cmp   eax,-1                    ; check for no change
        jz    getbrt                    ; no change, just return current setting
        mov   si,offset dac_default
        mov   di,offset dac_current
        cmp   eax,-2                    ; check for reset
        jnz   setbrt                    ; not reset, must be a value to set
        mov   eax,[ID_Brightness]       ; otherwise, we are resetting default
setbrt:
        mov   usr_brightness,eax  ; save current user value
        mov   cx,6
        not   al                ; invert (lower DAC values increase brightness)
        shl   ax,1              ; double to get DAC bias in range 0-512
brtloop:
        mov   dx,[si]           ; get the default setting for this DAC
        add   dx,ax             ; add the requested setting >> 2
        sub   dx,256            ; subtract off the norm value >> 2
        cmp   dx,mindacval      ; check to make sure we are not below min
        jge   chkbrtmax
        mov   dx,mindacval      ; force min value
        jmp   brtok
chkbrtmax:
        cmp   dx,maxdacval      ; check to make sure we are not above max
        jle   brtok
        mov   dx,maxdacval      ; force max value
brtok:
        mov   [di],dx           ; save the new setting
        add   si,2
        add   di,2
        loop  brtloop
getbrt:
        mov   eax,usr_brightness ; return the current user brightness value
        mov   GIX.SV_ret_brightness,eax

; now do the hue
        cmp   device_id,VCA_PAL ; Is this a PAL VCA card
        jne   hue_NTSC

        ; >>>---> not supported by PAL H/W <---<<<
        mov   eax,-1            ; Not support by H/W set to default always
        mov   usr_hue,eax       ; save current user value
        jmp   gethue
hue_NTSC:
        mov   eax,GIX.SV_set_hue; get the hue value to set
        cmp   eax,-1            ; check for no change
        jz    gethue            ; no change, just return current setting
        cmp   eax,-2            ; check for reset
        jnz   sethue            ; not reset, must be a value to set
        mov   eax,[ID_Hue]      ; otherwise, we are resetting default
sethue:
        mov   usr_hue,eax       ; save current user value
        shl   ax,1              ; make hue in range 0-512
        mov   dx,hue            ; get the default hue value
        add   dx,ax             ; add the requested setting >> 2
        sub   dx,256            ; subtract off the norm value >> 2

        cmp   dx,minhueval      ; check to make sure we are not below min
        jge   chkhuemax
        mov   dx,minhueval      ; force min value
        jmp   hueok
chkhuemax:
        cmp   dx,maxhueval      ; check to make sure we are not above max
        jle   hueok
        mov   dx,maxhueval      ; force max value
hueok:

        mov   c_hue,dx          ; save the new current value
gethue:
        mov   eax,usr_hue       ; return the current user hue value
        mov   GIX.SV_ret_hue,eax

; now do the saturation
        mov   eax,GIX.SV_set_saturation  ; get the sat value from parms
        cmp   eax,-1                     ; check for no change
        jz    getsat                     ; no change, just return current setting
        cmp   eax,-2                     ; check for reset
        jnz   setsat                     ; not reset, must be a value to set
        mov   eax,[ID_Saturation]        ; otherwise, we are resetting default
setsat:
        mov   usr_saturation,eax         ; save current user value
        shl   ax,1                       ; make saturation in range 0-512
        mov   dx,saturation              ; get the default saturation value
        add   dx,ax                      ; add the requested setting >> 2
        sub   dx,256                     ; subtract off the norm value >> 2

        cmp   dx,minsatval               ; check to make sure we are not below min
        jge   chksatmax
        mov   dx,minsatval               ; force min value
        jmp   satok
chksatmax:
        cmp   dx,maxsatval               ; check to make sure we are not above max
        jle   satok
        mov   dx,maxsatval               ; force max value
satok:
        mov   c_sat,dx                   ; save the new current value
getsat:
        mov   eax,usr_saturation         ; return the current user hue value
        mov   GIX.SV_ret_saturation,eax

; now do the contrast
        mov   eax,GIX.SV_set_contrast    ; get the contrast value from parms
        cmp   eax,-1                     ; check for no change
        jz    getcont                    ; no change, just return current setting
        cmp   eax,-2                     ; check for reset
        jnz   setcont                    ; not reset, must be a value to set
        xor   eax,eax                    ; reset default value...
        mov   ax,contrast                ; get the default contrast value
        mov   c_cont,ax                  ; save as new current value
        shr   eax,2                      ; get into 0-255 range
        mov   eax,[ID_Contrast]          ; use Contrast from Init instead
        mov   usr_contrast,eax           ; save current user value
        jmp   getcont
setcont:
        and   eax,0FFH                   ; limit to 0-255
        mov   usr_contrast,eax           ; save current user value
        shl   ax,2                       ; make contrast value in the range 0-1023
        cmp   ax,mincontval              ; check to make sure we are not below min
        jge   chkcontmax
        mov   ax,mincontval              ; force min value
        jmp   contok
chkcontmax:
        cmp   ax,maxcontval              ; check to make sure we are not above max
        jle   contok
        mov   ax,maxcontval              ; force max value
contok:
        mov   c_cont,ax                  ; save the new current value
getcont:
        mov   eax,usr_contrast           ; return the current user contrast value
        mov   GIX.SV_ret_contrast,eax
;
; current value block is set up, now program the DACs
;
        push  es                ; save request packet pointer
        push  bx                ; .
        mov   ax,ds             ; get es:si pointing to current dac block
        mov   es,ax
        mov   si,offset dac_current
        call  progdac
        pop   bx                ; restore request packet pointer
        pop   es

        sub   ax,ax                    ; indicate no error
        ret
CODE_75H ENDP

CODE_76H PROC NEAR
;-------------------- SET FPS to stream Image (76H) --------------------------

        LBegin 4h
        push  es
        push  bx

        mov   ax,word ptr GIO._Data+2 ; get address of data area
        mov   bx,word ptr GIO._Data   ;
        mov   es,ax                   ; es:bx-->data area


        mov   ebx,GIX.SF_Set_FPS      ; Stream Image every N Frames/Sec
        mov   [usr_FPS],bx

        sub   ax,ax                   ; indicate no error

code_76h_done:
        pop   bx                ; restore request packet pointer
        pop   es
        lend
        ret
CODE_76H ENDP





subttl OPEN Routine
page
;-------------------------------------------------------------------------------
; Procedure for handling OPEN for device
;-------------------------------------------------------------------------------
OPEN     PROC  NEAR
        ; Allocate and Initialize an Open Instance structure
        mov   ecx,SIZE OPEN_INSTANCE ; Size of storage to allocate
        mov   edi,-1
        ;         876543210
        mov   eax,000000010B ; Allocate in Global address space, fixed  storage
        mov   dl,DevHlp_VMAlloc
        call  device_hlp
        jc    OPENx                     ; Did we get the storage   Carry=1 is a failure

        ; Add new Stream Instance
        PUSHFD
        CLI                              ; Turn Off Interrupt (Critical Section)
        mov   fs,flatsel
        MOV   ECX,OI_List                ; Find first OI in the List
        mov   fs:[eax].OI_pNext,ECX      ; New OI points to old  Head of the OI_LIST
        MOV   OI_List,EAX                ; Add New OI at the head of the OI_LIST
        MOV   fs:[eax].OI_SI,0           ; Stream Instance
        mov   fs:[eax].OI_hStream,0      ;
        mov   dx,es:[bx+OC_FN_OFFSET]    ; System File Number
        MOV   fs:[eax].OI_FileNum,dx     ; Stream not active
        POPFD

         inc   VCA_opens                ; Count Number of Opens
         cmp   VCA_opens,1              ; Is the device already setup
         jne   OPEN_done                ; yes - skip setup
         push  es                       ; save request packet pointer
         push  bx
;
; Load the TARAM entries for the address range specified by SET CONFIGURATION
; if the adapter is configured with a full 640K aperature (40 16K pages).  If
; the adapter is configured with a 16K, 32K, or 64K aperature, the TARAM will
; not be initialized at device open time.  Instead, the TARAM will be
; configured whenever a bank selection is performed via IOCTL function code
; 71h.
;
         cmp   pages,40                ; card configured with a full aperature ?
         jz    taraminit
         jmp   ring3addr               ; no, don't set up the TARAM...
;
; The card is configured with a full aperature.  Set up the TARAM entries for
; the buffer.
;
taraminit:
         push  di                      ; save offset to structure in DI
         mov   ax,iobase               ; get I/O base address in DI
         mov   di,ax                   ; .
;
; Note the following code has the restriction that the 640K addressing
; window must be aligned on a 16K boundary in the physical address space
; and must not span TARAM quadrants (i.e. must be entirely within 0-4M, 4-8M,
; 8-12M, or 12-16M).
;
         mov   eax,DWORD PTR lsw_phys_add ; get the physical address
         shr   eax,14                  ; Get 16K segment number
         xchg  ah,al                   ; AH = TARAM address within quadrant
         and   al,03h                  ; AL = TARAM quadrant number
         mov   dx,6                    ;
         add   dx,di                   ; DX = reg 6 (TARAM address high/control)
         out   dx,al                   ; write TARAM quadrant # to register 6
         in    al,dx                   ; extra reg 6 read per tech ref

         mov   cx,pages                ; get count of 16K pages to set up
         mov   bl,ah                   ; BL = TARAM address within quadrant
         xor   bh,bh                   ; BH = VRAM block number counter = 0
tset1:
         mov   dx,7                    ; put TARAM address bits 0-7 in reg 7
         add   dx,di                   ; DX = reg 7 (TARAM address low)
         mov   al,bl                   ; .
         out   dx,al                   ; .


         mov   dx,4                    ; write control bits for this TARAM slot
         add   dx,di                   ; DX = reg 4 (TARAM data - control)
         mov   al,0A0H                 ; bank enable, image plane, linear addr
         out   dx,al                   ; .

         mov   al,bh                   ; convert block # to quotient/remainder
         xor   ah,ah                   ; AX = block number
         mov   dl,5                    ; DL = divisor (see tech ref p3-22)
         div   dl                      ; AL = quotient, AH = remainder
         shl   al,5                    ; get quotient in bits 7-5
         or    al,ah                   ; combine remainder and quotient
         mov   dx,3                    ; write VRAM block number for this TARAM slot
         add   dx,di                   ; DX = reg 3 (TARAM data - block number)
         out   dx,al                   ; .

         inc   bh                      ; increment VRAM block number
         inc   bl                      ; increment TARAM address
         loop  tset1                   ; loop for all TARAM entries

         mov   bx,di                   ; put IOBASE in BX
         pop   di                      ; restore structure offset in DI

ring3addr:
;
;        Create a 16:16 selector address to the buffer for ring 3 code to use
;
;        The ring 3 selector will reference a buffer that is 16, 32, or 64K
;        depending on the aperature size configured.  Only the first 64K
;        of a 640K aperature-configured card will be addressable with 16:16
;        addressing.
;
         mov   cx,pages                ; get number of pages
         shl   cx,14                   ; convert to aperature size
         mov   ax,msw_phys_add          ; convert real address of VRAM to
         mov   bx,lsw_phys_add          ; convert real address of VRAM to
         mov   dh,1                     ; read/write area
         mov   dl,DevHlp_PhysToUVirt    ; get a selector
         call  device_hlp               ;
         mov   ax,es                    ; save the returned selector
         mov   selector1,ax             ; save selector for VRAM window 1
;
;        Create a 32-bit linear address to the buffer for ring 3 code to use
;
        mov     edi, DWORD PTR lsw_phys_add ; get physical addr of buffer
        mov     buffer_phys, edi        ; save it

        mov     ax, ds
        mov     esi, offset buffer_phys ; this is the 32 bit offset (flat)
        mov     dl, DevHlp_VirttoLin
        call    device_hlp

        mov     edi, eax                 ; get pointer to physical address
        sub     ecx,ecx                  ; get number of pages
        mov     cx,pages                 ; .
        shl     ecx,14                   ; convert to aperature size
        mov     aper_size,ecx   ; save aperature size
        mov     eax, 10h        ; bit 4 = phys addr, bit 5 = 0 Global addr
        mov     dl,  DevHlp_VMAlloc
        call    device_hlp      ; Get Global Address
        mov     lin_addr, eax   ; store linear address of Super VIA memory


;
; Initialize current settings to default and program the DACs
;
        mov   ax,ds               ; set ES=DS
        mov   es,ax               ; .
        lea   si,dac_default          ; offset of default DAC settings
        lea   di,dac_current          ; offset of current DAC settings
        mov   cx,9                    ; count of DAC settings
        rep   movsw                   ; initialize current settings to default
        mov   si,OFFSET dac_current ; get es:si pointing to DAC calibration values
        call  progdac
;
; DACs are programmed and TARAM setup is complete, now enable
;   host memory access (see tech ref p3-20)
;
        mov   al,80H                  ; set memory enable
        mov   dx,iobase
        add   dx,6                    ; DX = reg 6 (TARAM address high/control)
        out   dx,al                   ;
        in    al,dx                   ; extra reg 6 read per tech ref
;
;        Set the control register
;
        mov   dx,iobase
        add   dx,14                   ; DX = reg 14 (Control)
        mov   al,58H                  ; bit 6,3 = 1 (NTSC, genlock, 565 format)
        out   dx,al                   ;
;
;        Set the capture control register (tech ref p.3-31)
;
;        Defaults:
;           Capture type is interlaced, 262.5 lines/field, both fields
;           sync lock position = 12 (per tech ref)
;
        mov   dx,iobase
        add   dx,12                   ; DX = reg 12 (capture control)
        mov   al,0CH                  ; bits 765 = 000, 5 lsb's = 12
        out   dx,al                   ;
;
; Now set live/capture mode
;
        mov   dx,iobase
        add   dx,15                   ; DX = reg 15 (Mode control)
        mov   al,06H                  ; bits 2-0 = 1 1 0 = live/capture mode
        out   dx,al                   ;

        pop   bx                      ; restore request packet pointer
        pop   es                      ;


OPEN_done:                              ; setup Complete

        ret                           ;
OPENx:   or    IP._Stat,error_s + general_failure


         RET
OPEN     ENDP
subttl CLOSE Routine
page
;-------------------------------------------------------------------------------
; Procedure for handling CLOSE for device
;-------------------------------------------------------------------------------
CLOSE    PROC  NEAR

;        int 3
         ; Remove  Stream Instance
         mov   fs,flatsel
         mov   cx,es:[bx+OC_FN_OFFSET]  ; System File Number
         call  REMOVE_OI

         cmp   eax,0                    ; 0 = Invalid Stream Handle
         je    CLOSEx

         ; Stop and deregister the stream for this instance
         mov   ecx,fs:[eax].OI_hStream
         cmp   ecx,0                    ; Is a stream Registered
         je    STREAM_GONE              ; No Stream registered
         call  far ptr STOP_STREAM
         call  far ptr DEREG_STREAM
STREAM_GONE:                            ;



         ; Free the OI  structure
         mov   dl,DevHlp_VMFree
         call  device_hlp
         jc    CLOSEx                   ; Did we free the storage   Carry=1 is a failure

         dec   VCA_opens                ; Count Number of Opens
         cmp   VCA_Opens,0              ; Is this the last Close
         jne   CLOSEx                   ; no

         ; Drop Addressability to the Cards Memory
         mov   selector1,0              ; Zero selector for VRAM window 1
         mov   eax,lin_addr             ; Free  address of Super VIA memory
         mov   lin_addr,0               ; Zero  address of Super VIA memory
         mov   dl,  DevHlp_VMFree
         call  device_hlp               ; Free Global Address of SuperVIA memory

CLOSEx:
         RET
CLOSE    ENDP

subttl IOCTL Routines


;---------------------------------------------------------------------------
; PROGDAC
;
; Program the DACs with specified data values
;
; INPUTS:
;
;   ES:SI = pointer to DAC calibration values
;
; OUTPUT: none
;---------------------------------------------------------------------------
PROGDAC proc  near
        mov   dx,iobase
        mov   bx,dx
        add   dx,7                    ; DX = DAC pointer register I/O port
        add   bx,10                   ; BX = DAC value register I/O port
        xor   ah,ah                   ; AH = DAC index
        mov   cx,16                   ; first 16 bytes calibration data
prgd1:
        mov   al,ah                   ; get the DAC index
        inc   ah                      ; and increment
        out   dx,al                   ; select DAC sub-address in reg 7
        xchg  bx,dx                   ; DX = DAC value register I/O port
        mov   al,es:[si]              ; get next DAC value
        inc   si                      ; and increment
        out   dx,al                   ; write the DAC value through reg 10
        xchg  bx,dx                   ; DX = DAC pointer register I/O port
        loop  prgd1
   ; handle "funny" contrast value conversion
        mov   al,ah                   ; get the DAC index for contrast
        out   dx,al                   ; select DAC sub-address in reg 7
        xchg  bx,dx                   ; DX = DAC value register I/O port
        mov   ax,es:[si]              ; get the DAC value for contrast
        shl   ax,1                    ; this puts contrast value 0-7 in AH
        and   ah,7                    ; (make sure memory value was in range)
        mov   al,7                    ; now invert so 0 = max contrast
        sub   al,ah                   ; . and 7 = min contrast
        out   dx,al                   ; write the contrast value through reg 10

        ret
PROGDAC endp

subttl Set Bank Number
page
;---------------------------------------------------------------------------
; SETBANKNUM
;
; Program the BANK Register with the specified value
;
; INPUTS:
;   ECX   = Bank Number
;
; OUTPUT: none
;---------------------------------------------------------------------------
SETBANKNUM proc  near
         push  eax
         push  ebx
         push  ecx
         push  edx
         push  edi
         pushfd
         cli

         mov   ax,iobase               ; get I/O base address in DI
         mov   di,ax                   ; .

         mov   eax,DWORD PTR lsw_phys_add ; get the physical address
         shr   eax,14                  ; Get 16K segment number
         xchg  ah,al                   ; AH = TARAM address within quadrant
         and   al,03h                  ; AL = TARAM quadrant number
         mov   dx,6                    ;
         add   dx,di                   ; DX = reg 6 (TARAM address high/control)
         out   dx,al                   ; write TARAM quadrant # to register 6
                                       ; (note that this disables host memory access)
         in    al,dx                   ; extra reg 6 read per tech ref

         mov   dl,ah                   ; DL = TARAM address within quadrant
         mov   eax,ecx                 ; get bank number to select
         mov   cx,pages                ; get count of 16K pages to set up
         mul   cl                      ; determine VRAM block number for bank

         mov   bl,dl                   ; BL = TARAM address within quadrant
         mov   bh,al                   ; BH = VRAM block number counter

banksel1:
         mov   dx,7                    ; put TARAM address bits 0-7 in reg 7
         add   dx,di                   ; DX = reg 7 (TARAM address low)
         mov   al,bl                   ; .
         out   dx,al                   ; .

         mov   dx,4                    ; write control bits for this TARAM slot
         add   dx,di                   ; DX = reg 4 (TARAM data - control)
         mov   al,0A0H                 ; bank enable, image plane, linear addr
         out   dx,al                   ; .

         mov   al,bh                   ; convert block # to quotient/remainder
         xor   ah,ah                   ; AX = block number
         mov   dl,5                    ; DL = divisor (see tech ref p3-22)
         div   dl                      ; AL = quotient, AH = remainder
         shl   al,5                    ; get quotient in bits 7-5
         or    al,ah                   ; combine remainder and quotient
         mov   dx,3                    ; write VRAM block number for this TARAM slot
         add   dx,di                   ; DX = reg 3 (TARAM data - block number)
         out   dx,al                   ; .

         inc   bh                      ; increment VRAM block number
         inc   bl                      ; increment TARAM address
         loop  banksel1                ; loop for all TARAM entries
;
; TARAM setup is complete, now enable host memory access (see tech ref p3-20)
;
         mov   al,80H                  ; set memory enable
         mov   dx,iobase
         add   dx,6                    ; DX = reg 6 (TARAM address high/control)
         out   dx,al                   ;
         in    al,dx                   ; extra reg 6 read per tech ref

         popfd
         pop   edi
         pop   edx
         pop   ecx
         pop   ebx
         pop   eax
         ret
SETBANKNUM endp

subttl LockMem
page

;********************** START OF SPECIFICATIONS ***************************
;*
;* SUBROUTINE NAME:  LockMem
;*
;* DESCRIPTIVE NAME:  Lock memory passed to PDD from process.
;*
;* FUNCTION: Lock the virtual linear addresses of a chunk of memory
;*            so that we can access them. It will also convert process
;*            memory to globale memory.
;*
;* ENTRY POINTS:   LockMemLong
;*
;* INPUT:
;*              AX:ESI = selector:offset of lock handle
;*              EBX = Linear address to lock
;*              ECX = Length to lock (will be rounded to next 4K boundary)
;*
;* EXIT-NORMAL: Carry Flag clear
;*              EAX = Global linear address of memory locked
;*
;* EXIT-ERROR:  Carry Flag Set
;*              EAX = error code
;*
;* SIDE EFFECTS:
;*              All registers are preserved, except for EAX
;*
;* MODIFICATION HISTORY:
;*     DATE      DEVELOPER     CHANGE DESCRIPTION
;*
;*********************** END OF SPECIFICATIONS ****************************
LockMem Proc NEAR
;        ASSUME cs:_TEXT,ds:_DATA,es:NOTHING,ss:NOTHING
      LOCK_RW         EQU     0000000000001000B     ; R/W access
      LOCK_LONG       EQU     0000000000010000B     ; Lock for long duration

        push    edi
        push    ebx
        push    ecx
        push    edx
        push    esi

        mov     edi,LOCK_RW OR LOCK_LONG ; r/w access & lock Long
;
; Get linear address of hlock. Needed for VMLock call
;
        mov     dl,DevHlp_VirtToLin
        call    device_hlp              ;
        jc      LockMem_err

;
; Lock the memory.
;
        mov     esi,eax                 ; lock handle
        mov     eax,edi                 ; flags:
        mov     edi,-1                  ; no page info returned
        mov     dl,DevHlp_VMLock
        call    device_hlp              ;
        jc      LockMem_err

;
; Need to do VMProcessToGlobal
;
        mov     eax,01h                 ; flag: writable
        mov     dl,DevHlp_VMProcessToGlobal
        call    device_hlp              ;
        jnc     LockMem_ret

LockMem_err:
;        mov     eax,1                  ; EAX has Error Code from DevHelp
LockMem_ret:
        pop     esi
        pop     edx
        pop     ecx
        pop     ebx
        pop     edi

        ret
LockMem endp

subttl UnLockMem
page

;********************** START OF SPECIFICATIONS ***************************
;*
;* SUBROUTINE NAME:  UnlockMem
;*
;* DESCRIPTIVE NAME:  Unlock memory
;*
;* FUNCTION: Unlock the virtual linear addresses of the memory we locked down.
;*
;* ENTRY POINTS:   UnlockMem
;*
;* INPUT:
;*              AX:ESI = selector:offset of lock handle
;*              EBX = offset of global linear to VMfree
;*
;* EXIT-NORMAL: Carry Flag clear
;*
;* EXIT-ERROR:  Carry Flag Set
;*              EAX = error code
;*
;* SIDE EFFECTS:
;*              All registers are preserved, except EAX
;*
;* MODIFICATION HISTORY:
;*     DATE      DEVELOPER     CHANGE DESCRIPTION
;*
;*********************** END OF SPECIFICATIONS ****************************
UnlockMem Proc NEAR
;        ASSUME cs:_TEXT,ds:_DATA,es:NOTHING,ss:NOTHING

        push    edx
        push    esi

;
; Do a VMFree (to undo VMProcessToGlobal)
;
        xchg    eax,ebx                         ; eax = linear addr to lock
        mov     dl,DevHlp_VMFree
        call    device_hlp              ;
        jc      UnlockMem_err

;
; Get linear address of hlock. Needed for VMLock call
;
        xchg    eax,ebx                         ; eax = selector of lock handle
        mov     dl,DevHlp_VirtToLin
        call    device_hlp              ;
        jc      UnlockMem_err

;
; Unlock the memory.
;
        mov     esi,eax                 ; lock handle
        mov     dl,DevHlp_VMUnlock
        call    device_hlp              ;
        jnc     UnlockMem_ret           ;

UnlockMem_err:
;        mov     eax,1                  ; EAX has Error Code from DevHelp
UnlockMem_ret:
        pop     esi
        pop     edx

        ret
UnlockMem endp


;***************************************************************************
;* FUNCTION:    Remove a Open Instance (OI) from the OI_LIST
;*
;* INPUT:
;*              CX  = OPEN Handle of the (OI) to be removed
;*
;* EXIT-NORMAL:
;*              EAX  = Buffer Address for OI
;*
;* EXIT_ERROR:
;*              EAX = 0   (OI not Found)
;***************************************************************************
Procedure REMOVE_OI,NEAR
        ASSUME cs:_TEXT,ds:DATA,es:NOTHING,ss:NOTHING

;       int 3
        PUSHFD
        PUSH  ECX
        PUSH  EDX
        CLI                                   ; Turn Off Interrupt (Critical Section)

        CALL  far ptr FIND_OI                 ; Is it In the List?
        CMP   EAX,0                           ; Is the List Empty
        JE   REMOVE_OI_Done                   ; Stream Handle - Not in List

REMOVE_OI_WALK:
        MOV   EAX,OI_LIST                     ; Get First OI in the OI_LIST
        MOV   EDX,0                           ; 0 = Delete from List Head
REMOVE_OI_NEXT:
        CMP   EAX,0                           ; Is the List Empty
        JE   REMOVE_OI_Done                   ; - Not in List

        cmp   fs:[eax].OI_FileNum,cx          ; Is this to correct OI
        je    REMOVE_OI_ITEM                  ; We Found the OI - Handle in List

        mov   edx,eax                         ; Remember Previous Element
        mov   eax,fs:[eax].OI_pNext           ; Try next OI
        jmp   REMOVE_OI_Next                  ; Loop until all OI(s) are checked

REMOVE_OI_ITEM:
        cmp   edx,0                           ; Is the Item at the List Head
        je    REMOVE_OI_HEAD                  ; Remove Element from the Head
        mov   ecx,fs:[eax].OI_pNext           ; Next Item after Item being Deleted
        mov   fs:[edx].OI_pNext,ecx           ; Previous points to new next
        Jmp   REMOVE_OI_Done                  ; All Done

REMOVE_OI_HEAD:
        mov   ecx,fs:[eax].OI_pNext           ; Next Item after Item being Deleted
        mov   OI_LIST,ECX                     ; Next point to new next Item
        Jmp   REMOVE_OI_Done                  ; All Done


REMOVE_OI_DONE:
        POP   EDX
        POP   ECX
        POPFD
        RET
EndProc REMOVE_OI

;***************************************************************************
;* FUNCTION:    Find a Open Instance (OI) in the OI_LIST
;*
;* INPUT:
;*              CX  = File Handle/Open Instance to Find
;*
;* EXIT-NORMAL: EAX  = pointer to OI
;*
;*
;* EXIT_ERROR:  EAX = 0 (not in the List)
;*
;***************************************************************************
Procedure FIND_OI,FAR
        ASSUME cs:_TEXT,ds:DATA,es:NOTHING,ss:NOTHING

        PUSHFD
        PUSH  ECX
        CLI                                   ; Turn Off Interrupt (Critical Section)

        MOV   EAX,OI_List                     ; Find first OI in the List
FIND_OI_Next:
        CMP   EAX,0                           ; Is list Empty?
        je    FIND_OI_NIL                     ; - Not in List

        cmp   fs:[eax].OI_FileNum,cx          ; Is this to correct OI
        je    FIND_OI_DONE                    ; We Found the OI

        mov   eax,fs:[eax].OI_pNext           ; Try next OI
        jmp   FIND_OI_Next                    ; Loop until all OI(s) are checked


FIND_OI_NIL:                                  ; Not in the List

FIND_OI_DONE:                                 ; We Found the OI


        POP   ECX
        POPFD
        RET
EndProc FIND_OI

;***************************************************************************
;* FUNCTION:    Stop a Stream
;*
;* INPUT:
;*              ECX  = hStream  handle of stream to stop
;*
;* EXIT-NORMAL: Carry flag is not set
;*
;*
;* EXIT_ERROR:  Carry flag is set
;*
;***************************************************************************
Procedure STOP_STREAM,FAR
        ASSUME cs:_TEXT,ds:DATA,es:NOTHING,ss:NOTHING

;       int 3
        push  eax
        sub   esp,size ddcmd_control_parm   ; Room for parm packet on stack
        lea   esi,[esp]                     ; Paramet Packet addr
        mov   ss:[esi].cont_ulFunction,DDCMD_CONTROL
        mov   ss:[esi].cont_hStream,ECX
        mov   ss:[esi].cont_hEvent,0
        mov   ss:[esi].cont_ulCmd,DDCMD_STOP
        mov   ss:[esi].cont_pParm,0
        mov   ss:[esi].cont_ulParmSize,0
        push  ss
        push  si
        call  IDC_ENTRY
        pop   si
        pop   ss
        add   esp,size ddcmd_control_parm   ; Room for parm packet on stack
        or    ax,dx                         ; check RC = no error on call
        clc                                 ; Assume no error
        cmp   ax,0
        je    stop_stream_exit              ; NO error
        stc                                 ; Opps an error occured
;       int 3
STOP_STREAM_EXIT:
        pop   eax
        RET
EndProc STOP_STREAM

;***************************************************************************
;* FUNCTION:    DEREGISTER a Stream
;*
;* INPUT:
;*              ECX  = hStream  handle of stream to Deregister
;*
;* EXIT-NORMAL: Carry flag is not set
;*
;*
;* EXIT_ERROR:  Carry flag is set
;*
;***************************************************************************
Procedure DEREG_STREAM,FAR
        ASSUME cs:_TEXT,ds:DATA,es:NOTHING,ss:NOTHING

;       int 3
        push  eax
        sub   esp,size ddcmd_deregister_parm  ; Room for parm packet on stack
        lea   esi,[esp]                       ; Paramet Packet addr
        mov   ss:[esi].dere_ulFunction,DDCMD_DEREG_STREAM
        mov   ss:[esi].dere_hStream,ECX
        push  ss
        push  si
        call  IDC_ENTRY
        pop   si
        pop   ss
        add   esp,size ddcmd_deregister_parm  ; Room for parm packet on stack
        or    ax,dx                           ; check RC = no error on call
        cmp   ax,0
        je    DEREG_STREAM_EXIT
        stc                                   ; Opps an error occured
;       int 3
DEREG_STREAM_EXIT:
        pop   eax
        RET
EndProc DEREG_STREAM

;-------------------------------------------------------------------------------
_TEXT ENDS
;    End of CODE segment
;
;*******************************************************************************
        END
