Tom Wellige  

About Me
Home
My Blog

Favourites
Books
Drink

Open Source
Miscellaneous
CAN M3S Driver
HPShell
Web DB Editor
Open Queue

Miscellaneous
Wiki
Bookmark

My Programming Page - VCAND




VCAND

Contents of this page

  • VCAND.ASM, Main module of Virtual Device Driver



VCAND.ASM

;****************************************************************************
;*                                                                          *
;*  Name:         VCAND.ASM - CAN VxD                                       *
;*                                                                          *
;*  Version:      1.00                                                      *
;*                                                                          *
;*  Date:         20.11.95                                                  *
;*                                                                          *
;*  Author:       Tom Wellige                                               *
;*                                                                          *
;*                Copyright (c) in 1995 by Dubin Institute of Technology.   *
;*                                                                          *
;*                All rights reserved.                                      *
;*                                                                          *
;*  Description:  Virtual Controller Area Network (CAN) Device Driver       *
;*                                                                          *
;*--------------------------------------------------------------------------*
;*                                                                          *
;*  Change log:                                                             *
;*                                                                          *
;*     DATE     REV                 DESCRIPTION                             *
;*  ----------- --- --------------------------------------------------------*
;*                                                                          *
;****************************************************************************

        PAGE 58,132                    ; memorypage setting

        TITLE VCAND                    ; name of this VxD

        .386p                          ; generate 386 code


;****************************************************************************
;*                            I N C L U D E S                               *
;****************************************************************************

        .XLIST
        INCLUDE VMM.INC                ; VM Manager
        INCLUDE VPICD.INC              ; IRQ Manager
        INCLUDE VSD.INC                ; Sound
        INCLUDE DEBUG.INC              ; Debug Stuff
        INCLUDE VCAND.INC              ; own definitions
        .LIST


;****************************************************************************
;*            V I R T U A L   D E V I C E   D E C L A R A T I O N           *
;****************************************************************************

Declare_Virtual_Device VXD, VCAND_VERMAJ, VCAND_VERMIN, VCAND_Control, \
                       VCAND_DEV_ID,, VCAND_API_Proc, VCAND_API_Proc


;****************************************************************************
;*                               D A T A                                    *
;****************************************************************************

VxD_IDATA_SEG
;       Initialization data here - discarded after Init_Complete

;****************************************************************************
;*           I N T E R R U P T   D E S C R I P T O R   T A B L E            *
;****************************************************************************

VCAND_IRQ_Desc  VPICD_IRQ_Descriptor 

VxD_IDATA_ENDS


VxD_DATA_SEG
;       Normal Data here

;****************************************************************************
;*                      A P I   J U M P   T A B L E                         *
;****************************************************************************

VCAND_API_Table label DWORD                              ;  Function No.:

        dd      offset32        VCAND_Get_Version        ;  00h
        dd      offset32        VCAND_Set_Filter         ;  01h
        dd      offset32        VCAND_Get_Filter         ;  02h
        dd      offset32        VCAND_Reset_Filter       ;  03h
        dd      offset32        VCAND_Set_CONT_REG       ;  04h
        dd      offset32        VCAND_Set_COMM_REG       ;  05h
        dd      offset32        VCAND_Set_ACC_REG        ;  06h
        dd      offset32        VCAND_Set_ACM_REG        ;  07h
        dd      offset32        VCAND_Set_BT0_REG        ;  08h
        dd      offset32        VCAND_Set_BT1_REG        ;  09h
        dd      offset32        VCAND_Set_OUTP_REG       ;  0Ah
        dd      offset32        VCAND_Set_CLKD_REG       ;  0Bh
        dd      offset32        VCAND_Get_CONT_REG       ;  0Ch
        dd      offset32        VCAND_Get_STAT_REG       ;  0Dh
        dd      offset32        VCAND_Get_INT_REG        ;  0Eh
        dd      offset32        VCAND_Get_ACC_REG        ;  0Fh
        dd      offset32        VCAND_Get_ACM_REG        ;  10h
        dd      offset32        VCAND_Get_BT0_REG        ;  11h
        dd      offset32        VCAND_Get_BT1_REG        ;  12h
        dd      offset32        VCAND_Get_OUTP_REG       ;  13h
        dd      offset32        VCAND_Get_CLKD_REG       ;  14h
        dd      offset32        VCAND_Get_Counter        ;  15h
        dd      offset32        VCAND_Reset_Counter      ;  16h
        dd      offset32        VCAND_Allocate_Buffer    ;  17h
        dd      offset32        VCAND_Free_Buffer        ;  18h
        dd      offset32        VCAND_Mask_IRQ           ;  19h
        dd      offset32        VCAND_Unmask_IRQ         ;  1Ah
        dd      offset32        VCAND_Get_Status         ;  1Bh
        dd      offset32        VCAND_Reset              ;  1Ch
        dd      offset32        VCAND_Update_Timebase    ;  1Dh
        dd      offset32        VCAND_Receive_Messages   ;  1Eh
        dd      offset32        VCAND_Transmit_Messages  ;  1Fh
        dd      offset32        VCAND_Set_RX_HWND        ;  20h
        dd      offset32        VCAND_Set_TX_HWND        ;  21h
        dd      offset32        VCAND_Register_Callback  ;  22h

VCAND_Max_API = ($ - VCAND_API_Table) / 4 - 1

VxD_DATA_ENDS


VxD_LOCKED_DATA_SEG
;       Pagelocked data here - try to keep this to a minimum.

VCAND_Node1             dd  0          ; handle to VCAND_Data for CAN 1
VCAND_Node2             dd  0          ; handle to VCAND_Data for CAN 2
VCAND_Node3             dd  0          ; handle to VCAND_Data for CAN 3
VCAND_Node4             dd  0          ; handle to VCAND_Data for CAN 4
VCAND_Node5             dd  0          ; handle to VCAND_Data for CAN 5
VCAND_Node6             dd  0          ; handle to VCAND_Data for CAN 6
VCAND_Node7             dd  0          ; handle to VCAND_Data for CAN 7
VCAND_Node8             dd  0          ; handle to VCAND_Data for CAN 8
VCAND_Node9             dd  0          ; handle to VCAND_Data for CAN 9

VCAND_Node              dd  0          ; handle to the actual VCAND_Data
VCAND_Node_Ptr          dd  ?          ; points to actual VCAND_Node variable
VCAND_Num_Of_Nodes      dw  0          ; number of nodes

VCAND_Dummy1            dd  0          ; push/pop variable in API functions
VCAND_Dummy2            dd  0          ; push/pop variable in API functions

VCAND_Ini_Str_Ptr       dd  0          ; points actual VCAND_Ini_ string
VCAND_Ini_Reg_Ptr       dd  0          ; points actual Register in VCAND_Data

VCAND_Sys_VM            dd  0          ; System VM handle
VCAND_Cur_VM            dd  0          ; the current VM

VCAND_PostMsg_Off32     dd  0          ; CAN.DLL's post message addr
VCAND_PostMsg_Seg       dw  0

VxD_LOCKED_DATA_ENDS



;****************************************************************************
;*                 I N I T I A L I Z A T I O N   C O D E                    *
;* ------------------------------------------------------------------------ *
;*   Code in the initialization segment is discarded after Init_Complete    *
;****************************************************************************

VxD_ICODE_SEG

;****************************************************************************
;*                                                                          *
;*  VMM: VCAND_Device_Init                                                  *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This function inits the driver.                                     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX = System VM handle                                              *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Carry clear to indicate load success                                *
;*      Carry set to abort loading this VxD                                 *
;*                                                                          *
;*  USES:                                                                   *
;*      flags                                                               *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Device_Init

        mov     [VCAND_Sys_VM], ebx             ; save Sys_VM
        mov     [VCAND_Ini_Str_Ptr], OFFSET32 VCAND_Ini_1_IRQ
                                                ; pointer to first Ini string
        mov     [VCAND_Node_Ptr], OFFSET32 VCAND_Node1
                                                ; points to Node1 var

Init_Node:
        inc     [VCAND_Num_Of_Nodes]            ; a new node !
        VMMCall _HeapAllocate, <[VCAND_Data_Size], HeapZeroInit>
        cmp     eax, 0
        jnz     short Init_Node_Save
        jmp     Init_Failed
Init_Node_Save:
        mov     [VCAND_Node], eax
        mov     bx, [VCAND_Num_Of_Nodes]
        mov     [eax.VCAND_Data.CAN], bx        ; save CAN ID number
        mov     ebx, [VCAND_Node_Ptr]
        mov     [ebx], eax                      ; save Node in Node"x" var
        add     [VCAND_Node_Ptr], 4             ; points to Node"x+1" var


Init_Filter:
        mov     ebx, [VCAND_Node]
        VMMCall _HeapAllocate, <[VCAND_Filter_Size], HeapZeroInit>
        cmp     eax, 0                          ; success ?
        jnz     short Init_Filter_Save
        bts     [ebx.VCAND_Data.Status], ST_ERROR ; set ERROR status
        jmp     short Init_IRQ
Init_Filter_Save:
        mov     [ebx.VCAND_Data.Filter], eax    ; save pointer to filter


Init_IRQ:
        mov     eax, -1
        mov     esi, OFFSET32 VCAND_Ini_Profile
        mov     edi, [VCAND_Ini_Str_Ptr]        ; points on VCAND_Ini_x_IRQ
        VMMCall Get_Profile_Hex_Int             ; get defined IRQ
        cmp     eax, -1
        jnz     short Init_IRQ_Save             ; not found or no value
        mov     eax, DEFAULT_IRQ                ; use default value
Init_IRQ_Save:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.IRQ], ax        ; save it


Init_BTR0:
        add     [VCAND_Ini_Str_Ptr], 15         ; points on VCAND_Ini_x_BTR0
        mov     eax, -1
        mov     edi, [VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Hex_Int             ; get defined BTR0 value
        cmp     eax, -1
        jnz     short Init_BTR0_Save            ; not found or no value
        mov     eax, DEFAULT_BTR0               ; use default value
Init_BTR0_Save:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.BTR0], ax       ; save it


Init_BTR1:
        add     [VCAND_Ini_Str_Ptr], 15         ; points on VCAND_Ini_x_BTR1
        mov     eax, -1
        mov     edi, [VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Hex_Int             ; get defined BTR1 value
        cmp     eax, -1
        jnz     short Init_BTR1_Save            ; not found or no value
        mov     eax, DEFAULT_BTR1               ; use default value
Init_BTR1_Save:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.BTR1], ax       ; save it


Init_OCR:
        add     [VCAND_Ini_Str_Ptr], 15         ; points on VCAND_Ini_x_OCR
        mov     eax, -1
        mov     edi, [VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Hex_Int             ; get defined OCR value
        cmp     eax, -1
        jnz     short Init_OCR_Save             ; not found or no value
        mov     eax, DEFAULT_OCR                ; use default value
Init_OCR_Save:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.OCR], ax        ; save it


Init_BufSize:
        add     [VCAND_Ini_Str_Ptr], 15         ; ptr to VCAND_Ini_x_BufSize
        mov     eax, -1
        mov     edi,[VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Decimal_Int         ; get defined BufSize
        cmp     eax, -1
        jnz     short Init_BufSize_Save         ; not found or no value
        mov     eax, DEFAULT_BufSize            ; use default value
Init_BufSize_Save:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.BufSize], eax   ; save it


Init_Port:
        add     [VCAND_Ini_Str_Ptr], 15         ; points on VCAND_Ini_x_Port
        mov     eax, -1
        mov     edi, [VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Hex_Int             ; get defined Port
        cmp     eax, -1
        jnz     short Init_Reg_Vars             ; not found or no value
        mov     eax, DEFAULT_Port               ; use default value


Init_Reg_Vars:
        mov     ebx, [VCAND_Node]
        mov     cx, 30                          ; fill up to RXB8 Register
Init_Set_Reg_Var:
        mov     [ebx], ax                       ; save address in reg var
        add     ebx, 2                          ; set ptr to next reg var
        inc     ax                              ; set next address
        dec     cx
        jnz     short Init_Set_Reg_Var          ; ready ?
        inc     ax
        mov     [ebx], ax                       ; 1 byte gap RXB8 - CLKD_REG


Init_Controller:
        mov     ebx, [VCAND_Node]
        mov     dx, [ebx.VCAND_Data.CONT_REG]
        mov     cx, 01h                         ; set RESET-REQUEST to
        call    VCAND_Set_Reg                   ; configure the controller

        mov     dx, [ebx.VCAND_Data.ACC_REG]
        mov     cx, 0FFh                        ; acceptance register
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.ACM_REG]
        mov     cx, 0FFh                        ; all messages accepted
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.BT0_REG]
        mov     cx, [ebx.VCAND_Data.BTR0]       ; bus timing register 0
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.BT1_REG]
        mov     cx, [ebx.VCAND_Data.BTR1]       ; bus timing register 1
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.OUTP_REG]
        mov     cx, [ebx.VCAND_Data.OCR]        ; output control register
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.CONT_REG]   ; release reset, all
        mov     cx, 00h                         ; interrupts disabled
        call    VCAND_Set_Reg

        mov     dx, [ebx.VCAND_Data.INT_REG]
        call    VCAND_Get_Reg
        cmp     ax, 0E0h                        ; card installed ?
        jz      short Init_Virt_IRQ
        bts     [ebx.VCAND_Data.Status], ST_ERROR ; set ERROR status

Init_Virt_IRQ:
        mov     ebx, [VCAND_Node]
        xor     eax, eax
        mov     ax, [ebx.VCAND_Data.IRQ]        ; copy IRQ num in ax
        mov     cx, [VCAND_Num_Of_Nodes]
        cmp     cx, 01h                         ; is this the first card ?
        jz      short Init_Virt_IRQ_Virtualize  ;   yes - virtualize IRQ!
                                                ;   no  - so check if this
        call    VCAND_Check_If_IRQ_Is_Used      ;         IRQ already used ?
        jc      short Init_Virt_IRQ_Is_Used

Init_Virt_IRQ_Virtualize:
        mov     edi, OFFSET32 VCAND_IRQ_Desc    ; point to vpicd struct
        mov     [edi.VID_IRQ_Number], ax        ; save IRQ Number here
        VxDCall VPICD_Virtualize_IRQ            ; set up callbacks
        jc      short Init_Virt_IRQ_Error       ; error ?
        mov     [ebx.VCAND_Data.IRQ_Handle],eax ; save handle
        VxDCall VPICD_Physically_Mask           ; mask interrupt
        jmp     short Init_Error_Check

Init_Virt_IRQ_Is_Used:
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.IRQ_Handle],eax ; save the IRQ handle
        jmp     short Init_Error_Check

Init_Virt_IRQ_Error:
        bts     [ebx.VCAND_Data.Status], ST_ERROR ; set ERROR status


Init_Error_Check:
        bt      [ebx.VCAND_Data.Status], ST_ERROR ; ERROR status ?
        jc      short Init_Test_Next_Card
        bts     [ebx.VCAND_Data.Status], ST_INIT  ; set INIT status


Init_Test_Next_Card:
        mov     ax, [VCAND_Num_Of_Nodes]
        cmp     ax, 9                           ; is this the 9th card ?
        jz      short Init_All_Done

        add     [VCAND_Ini_Str_Ptr], 15         ; points on VCAND_Ini_x+1_IRQ
        mov     eax, -1
        mov     edi,[VCAND_Ini_Str_Ptr]
        VMMCall Get_Profile_Hex_Int
        cmp     eax, -1
        jnz     Init_Node                       ; get data for next card


Init_Idle_Callback:
        mov      esi, OFFSET32 VCAND_Idle_Handler
        VMMCall  Call_When_Idle
        jnc      short Init_All_Done
        bts      [ebx.VCAND_Data.Status], ST_ERROR


Init_All_Done:
        mov     ax, [ebx.VCAND_Data.Status]
        Mono_Out "VCAND_Device_Init: all done, status of last card #AX, Node #EBX"
        Mono_Out " "
        clc                                     ; no errors - load VxD
        jmp     short Init_Exit

Init_Failed:
        Mono_Out "VCAND_Device_Init: failed !"
        Mono_Out " "
        stc                                     ; errors - don't load VxD

Init_Exit:
        ret

EndProc VCAND_Device_Init



;****************************************************************************
;*                                                                          *
;*  VCAND_Check_If_IRQ_Is_Used                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This function checks, if the given IRQ is already used from another *
;*      CAN card (node) or not. This information is needed because an IRQ   *
;*      whih is already used by a CAN card is also already virtualized.     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      AX              :       IRQ                                         *
;*                                                                          *
;*  EXIT:                                                                   *
;*      EAX             :       IRQ_Handle or zero.                         *
;*      Carry Flag      :       set if IRQ is already used                  *
;*                                                                          *
;*  USES:                                                                   *
;*      EAX, BX, ECX, Flags                                                 *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Check_If_IRQ_Is_Used

        mov     edx, [VCAND_Node_Ptr]           ; save current VCAND_Node_Ptr
        push    edx
        mov     [VCAND_Node_Ptr], OFFSET32 VCAND_Node1
        mov     bx, 1h

Check_Node:
        mov     ecx, [VCAND_Node_Ptr]
        mov     dx, [ecx.VCAND_Data.IRQ]
        cmp     dx, ax                          ; this IRQ = given IRQ ?
        jz      short Check_Used_IRQ            ; yes, this IRQ is used

        add     [VCAND_Node_Ptr], 4             ; points to Node"x+1" var
        inc     bx
        cmp     bx, [VCAND_Num_Of_Nodes]        ; current node ?
        jnz     short Check_Node


Check_Not_Used_IRQ:
        clc                                     ; clear carry flag
        jmp     short Check_Exit

Check_Used_IRQ:
        mov     eax, [ecx.VCAND_Data.IRQ_Handle]; return IRQ handle
        stc                                     ; set carry flag

Check_Exit:
        pop     edx
        mov     [VCAND_Node_Ptr], edx           ; restore VCAND_Node_Ptr
        ret

EndProc VCAND_Check_If_IRQ_Is_Used


VxD_ICODE_ENDS


;****************************************************************************
;*                     P A G E   L O C K E D   C O D E                      *
;****************************************************************************

VxD_LOCKED_CODE_SEG

;****************************************************************************
;*                                                                          *
;*  VMM: VCAND_Control                                                      *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This is a call-back routine to handle the messages that are sent    *
;*      to VxD's to control system operation.                               *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EAX = Message number                                                *
;*      EBX = VM Handle                                                     *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Control

        Control_Dispatch Device_Init, VCAND_Device_Init

        clc
        ret

EndProc VCAND_Control



;****************************************************************************
;*                                                                          *
;*  VMM: VCAND_Idle_Handler                                                 *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This is a call-back routine the VMM calls when Windows is in        *
;*      idle mode. VCAND uses this callback to inform an application        *
;*      if a message to this application has been lost. This can happen     *
;*      when Windows wasn't fast enough to handle a previous message.       *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX = System VM handle                                              *
;*      EBP = Client register structure.  Return with carry set to pass the *
;*            call to the next handler.  Return with carry clear to "eat"   *
;*            the call-back and indicate the System VM is not idle.         *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Idle_Handler

        mov     cx, [VCAND_Num_Of_Nodes]
        mov     dx, 1

Idle_Get_Node:
        mov     bx, dx
        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      short Idle_Exit

        bt      [eax.VCAND_Data.Status], ST_INIT
        jnc     short Idle_Check_Node

        bt      [eax.VCAND_Data.Status], ST_POST_MESSAGES
        jnc     short Idle_Check_Node           ; post message callback ?

Idle_Check_Lost:
        bt      [eax.VCAND_Data.Status], ST_MESSAGE_LOST
        jnc     short Idle_Check_Node
        btr     [eax.VCAND_Data.Status], ST_MESSAGE_LOST
        mov     ebx, eax
        mov     [ebx.VCAND_Data.Message], can_MESSAGE_LOST
        call    VCAND_Post_Message              ; post WM_CAN message

Idle_Check_Node:
        cmp     cx, dx                          ; current node = last node ?
        je      short Idle_Exit
        inc     dx
        jmp     short Idle_Get_Node             ; get next node

Idle_Exit:
        or      [ebp.Client_Flags], CF_Mask     ; set the client carry flag
        ret

EndProc VCAND_Idle_Handler



;****************************************************************************
;*  IRQ: VCAND_Hw_Int_Proc                                                  *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Hardware interrupt handler. Called by VPICD. This is the so called  *
;*      Interrupt Service Routine ISR.                                      *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EAX             :       IRQ handle                                  *
;*      EBX             :       current VM handle                           *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Carry Flag      :       clc if IRQ successful processed             *
;*                              stc if IRQ unsuccessful processed           *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Hw_Int_Proc

        pushad                                  ; save 32 bit registers
        mov     ecx, eax                        ; save IRQ handle

        mov     [VCAND_Cur_VM], ebx

        call    VCAND_Get_Node_By_IRQ_Handle    ; get first node

ISR_Node_Check:
        mov     ebx, [VCAND_Node]
        mov     dx, [ebx.VCAND_Data.INT_REG]    ; get address of INT_REG
        in      al, dx                          ; read INT_REG
        test    ax, 1Fh                         ; is an INT bit set ?
        jnz     short ISR_Node_Found            ; yes, this is the node which
                                                ; caused the interrupt
        mov     ebx, ecx                        ; no, look for next node
        call    VCAND_Get_Next_Node_By_IRQ_Handle
        cmp     eax, 0                          ; is there a next node ?
        jz      ISR_Exit                        ; no  -> "phantom-IRQ"
        jmp     short ISR_Node_Check            ; yes -> check this node


ISR_Node_Found:
        mov     ebx, [VCAND_Node]
        bt      [ebx.VCAND_Data.Status], ST_IRQ ; IRQ status ?
        jnc     ISR_Exit

        test    ax, 04h                         ; error interrupt ?
        jnz     ISR_Error
        test    ax, 08h                         ; overrun interrupt ?
        jnz     ISR_Overrun
        test    ax, 01h                         ; receive interrupt ?
        jnz     short ISR_Receive
        test    ax, 02h                         ; transmit interrupt ?
        jnz     ISR_Transmit
        test    ax, 10h                         ; wake up interrupt ?
        jnz     ISR_Wake_Up


ISR_Receive:

ISR_Receive_Get_ID:
        mov     dx, [ebx.VCAND_Data.RRTR_REG]
        xor     ecx, ecx
        xor     ax, ax
        in      al, dx                          ; ID bits 0..2 in RRTR_REG
        shr     ax, 5                           ; shift to correct position
        mov     cx, ax                          ; save ID bits 0..2 in cx
        xor     ax, ax
        mov     dx, [ebx.VCAND_Data.RXID_REG]
        in      al, dx                          ; ID bits 3..10 in RXID_REG
        shl     ax, 3                           ; shift to correct position
        or      cx, ax                          ; complete ID in CX !

ISR_Receive_Filter_Check:
        mov     eax, [ebx.VCAND_Data.Filter]
        bt      [eax], ecx                      ; is msg in filter ?
        jnc     short ISR_Receive_RX_Check
        inc     [ebx.VCAND_Data.Num_Filtered]
        jmp     ISR_Receive_Ready

ISR_Receive_RX_Check:
        mov     eax, [ebx.VCAND_Data.BufSize]
        cmp     [ebx.VCAND_Data.Num_RX], eax
        jge     short ISR_Receive_Check_Number
        inc     [ebx.VCAND_Data.Num_RX]

ISR_Receive_Check_Number:
        mov     eax, [ebx.VCAND_Data.Num_RX]
        cmp     ax, [ebx.VCAND_Data.RX_HWND_Num]
        jng     short ISR_Receive_Save_Message  ; RX_HWND_Num msgs available?
        bt      [ebx.VCAND_Data.Status], ST_REQUEST_SEND
        jc      short ISR_Receive_Save_Message  ; CM_REQUEST_MESSAGES send ?
        bts     [ebx.VCAND_Data.Status], ST_REQUEST_SEND
        mov     [ebx.VCAND_Data.Message], can_REQUEST_MESSAGES
        call    VCAND_Post_Message              ; post WM_CAN message

ISR_Receive_Save_Message:
        mov     edx, [ebx.VCAND_Data.RX_Write]  ; pointer to recv buffer

        mov     [edx.VCAND_Message.ID], cx      ; save message id

        mov     ecx, edx                        ; save RX_Write in ecx
        xor     ax, ax
        mov     dx, [ebx.VCAND_Data.RRTR_REG]
        in      al, dx                          ; read RXID buffer
        mov     edx, ecx                        ; restore RW_Write

        xor     cl, cl
        bt      al, 4                           ; rtr bit = 1 ?
        rcl     cl, 1                           ; copy carry to cl.0
        mov     [edx.VCAND_Message.RTR], cl     ; save message rtr
        and     ax, 0Fh                         ; mask out id and rtr
        mov     [edx.VCAND_Message.DLC], al     ; save message dlc

        VMMCall Get_System_Time                 ; get system time
        mov     ecx, [ebx.VCAND_Data.Time_Base] ; get time base
        sub     eax, ecx                        ; system time - time base
        mov     [edx.VCAND_Message.Time], eax   ; save message time
        mov     ecx, edx                        ; save RX_Write in ecx

        lea     edi, [ecx] + 4                  ; save b1..b4 here
        mov     dx, [ebx.VCAND_Data.RXB1]       ; port address of RXB1
        insd                                    ; read and save b1..b4
        lea     edi, [ecx] + 8                  ; save b5..b8 here
        mov     dx, [ebx.VCAND_Data.RXB5]       ; port address of RXB5
        insd                                    ; read and save b5..b8

ISR_Receive_Inc_RX_Write:
        add     ecx, [VCAND_Message_Size]       ; inc RX_Write
        cmp     ecx, [ebx.VCAND_Data.RX_Top]    ; RX_Write = RX_Top ?
        jne     short ISR_Receive_Overrun_Check
        mov     ecx, [ebx.VCAND_Data.RX_Bottom] ; set RX_Write = RX_Bottom

ISR_Receive_Overrun_Check:
        cmp     ecx, [ebx.VCAND_Data.RX_LastMsg] ; RX_Write = RX_LastMsg ?
        jne     short ISR_Receive_No_Overrun
        mov     [ebx.VCAND_Data.Message], can_OVERRUN
        call    VCAND_Post_Message              ; post WM_CAN message
        inc     [ebx.VCAND_Data.Num_Overrun]

ISR_Receive_No_Overrun:
        mov     [ebx.VCAND_Data.RX_Write], ecx  ; save new RX_Write pointer

ISR_Receive_Ready:
        jmp     short ISR_Clear_Buffer


ISR_Transmit:
        call    VCAND_Send_Message              ; send one message
        jmp     short ISR_Exit

ISR_Error:
        inc     [ebx.VCAND_Data.Num_Error]
        mov     [ebx.VCAND_Data.Message], can_ERROR
        call    VCAND_Post_Message              ; post WM_CAN message
        jmp     short ISR_Exit

ISR_Overrun:
        inc     [ebx.VCAND_Data.Num_Overrun]
        mov     [ebx.VCAND_Data.Message], can_OVERRUN
        call    VCAND_Post_Message              ; post WM_CAN message
        jmp     short ISR_Clear_Buffer

ISR_Wake_Up:
        inc     [ebx.VCAND_Data.Num_Wake_Up]
        mov     [ebx.VCAND_Data.Message], can_WAKEUP
        call    VCAND_Post_Message              ; post WM_CAN message
        jmp     short ISR_Exit


ISR_Clear_Buffer:
        mov     ax, 0Ch
        mov     dx, [ebx.VCAND_Data.COMM_REG]
        out     dx, al                          ; release receive buffer

        mov     dx, [ebx.VCAND_Data.STAT_REG]
        in      al, dx
        test    al, 01h                         ; message in 2nd buffer ?
        jnz     ISR_Receive

ISR_Exit:
        mov     dx, [ebx.VCAND_Data.INT_REG]
        in      al, dx                          ; clear interrupt register

        popad                                   ; restore 32 bit register
        VxDCall VPICD_Phys_EOI                  ; unmask IRQ in VPICD
        clc                                     ; IRQ successful handled
        ret

EndProc VCAND_Hw_Int_Proc



;****************************************************************************
;*                                                                          *
;*  VCAND_Get_Node_By_IRQ_Handle                                            *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns in EAX and VCAND_Node variable the handle to the node which *
;*      IRQ_Handle is given in EBX. Returns zero and Carry flag set if no   *
;*      Node with this IRQ_Handle found.                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EAX             :       IRQ Handle.                                 *
;*                                                                          *
;*  EXIT:                                                                   *
;*      VCAND_Node      :       Handle to Node or zero.                     *
;*      EAX             :       Handle to Node or zero.                     *
;*      Carry Flag      :       Set if no Node with this IRQ_Handle found.  *
;*                                                                          *
;*  USES:                                                                   *
;*      EAX, EBX                                                            *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Node_By_IRQ_Handle

        push    ecx
        push    edx

        mov     [VCAND_Node_Ptr], OFFSET32 VCAND_Node1
                                                ; points to Node1 var

Get_Node_IRQ_Compare:
        mov     edx, [VCAND_Node_Ptr]
        mov     ebx, [edx]
        test    ebx, 0FFFFFFFFh                ; exist Node ?
        jz      short Get_Node_IRQ_Failed
        mov     ecx, [ebx.VCAND_Data.IRQ_Handle]
        cmp     ecx, eax                       ; current IRQ = searched IRQ ?
        jz      short Get_Node_IRQ_Success

        add     [VCAND_Node_Ptr], 4            ; get next node
        jmp     short Get_Node_IRQ_Compare

Get_Node_IRQ_Failed:
        stc                                    ; set carry flag - error!
        jmp     short Get_Node_IRQ_Exit

Get_Node_IRQ_Success:
        clc                                    ; clear carry flag - success!

Get_Node_IRQ_Exit:
        mov     [VCAND_Node], ebx              ; save handle in VCAND_Node
        mov     eax, ebx
        pop     edx
        pop     ecx
        ret

EndProc VCAND_Get_Node_By_IRQ_Handle



;****************************************************************************
;*                                                                          *
;*  VCAND_Get_Next_Node_By_IRQ_Handle                                       *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns in EAX and VCAND_Node variable the handle to the node which *
;*      IRQ_Handle is given in EBX. Also VCAND_Node_Ptr points not to       *
;*      VCAND_Node1. Returns zero and Carry flag set if there is no more    *
;*      Node with this IRQ_Handle. This function should only used directly  *
;*      after a VCAND_Get_Node_By_IRQ_Handle call since there is no search  *
;*      initialization.                                                     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       IRQ Handle.                                 *
;*                                                                          *
;*  EXIT:                                                                   *
;*      VCAND_Node      :       Handle to Node or zero.                     *
;*      EAX             :       Handle to Node or zero.                     *
;*      Carry Flag      :       Set on error.                               *
;*                                                                          *
;*  USES:                                                                   *
;*      EAX, EBX                                                            *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Next_Node_By_IRQ_Handle

        push    ecx
        push    edx

Get_Next_Node_IRQ_Compare:
        mov     edx, [VCAND_Node_Ptr]
        mov     eax, [edx]
        test    eax, 0FFFFFFFFh                ; exist Node ?
        jz      short Get_Next_Node_IRQ_Failed
        mov     ecx, [eax.VCAND_Data.IRQ_Handle]
        cmp     ecx, ebx                       ; current IRQ = searched IRQ ?
        jz      short Get_Next_Node_IRQ_Success

        add     [VCAND_Node_Ptr], 4            ; get next node
        jmp     short Get_Next_Node_IRQ_Compare

Get_Next_Node_IRQ_Failed:
        stc                                    ; set carry flag - error!
        jmp     short Get_Next_Node_IRQ_Exit

Get_Next_Node_IRQ_Success:
        clc                                    ; clear carry flag - success!

Get_Next_Node_IRQ_Exit:
        mov     [VCAND_Node], eax              ; save handle in VCAND_Node
        pop     edx
        pop     ecx
        ret

EndProc VCAND_Get_Next_Node_By_IRQ_Handle



;****************************************************************************
;*                                                                          *
;*  VCAND_Send_Message                                                      *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Copy the message in TX_Buffer at TX_Read position to the controller *
;*      transmit buffer and forces the chip to transmit this message. If    *
;*      no messages to send, the function reset the ST_SEND status bit.     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       VCAND_Data                                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Carry clear     :       Success                                     *
;*      ST_SEND         :       1 if more messages to send, 0 if not        *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Send_Message

        cmp     [ebx.VCAND_Data.Num_TX], 0      ; messages to send ?
        jne     short Send_Message_Copy
        btr     [ebx.VCAND_Data.Status], ST_SEND ; clear ST_SEND flag
        mov     ecx, [ebx.VCAND_Data.TX_LastMsg]
        mov     [ebx.VCAND_Data.TX_Read], ecx
        mov     [ebx.VCAND_Data.Message], can_SEND_MESSAGES
        call    VCAND_Post_Message              ; post WM_CAN message
        jmp     short Send_Message_Exit

Send_Message_Copy:
        dec     [ebx.VCAND_Data.Num_TX]

        mov     ecx, [ebx.VCAND_Data.TX_Read]   ; ptr to message in ebx
        mov     dx, [ebx.VCAND_Data.TXID_REG]
        mov     ax, [ecx.VCAND_Message.ID]
        shr     ax, 3                           ; ID.3-ID.10
        out     dx, al                          ; write to TXID_REG

        mov     ax, [ecx.VCAND_Message.ID]
        and     ax, 07h                         ; delete ID.3-ID.10
        shl     ax, 1                           ; shift left for RTR
        or      al, [ecx.VCAND_Message.RTR]     ; copy RTR
        shl     ax, 4                           ; shift left for DLC
        or      al, [ecx.VCAND_Message.DLC]     ; copy DLC
        mov     dx, [ebx.VCAND_Data.TRTR_REG]
        out     dx, al                          ; write TRTR_REG

        add     ecx, 4                          ; points to first data
        mov     dx, [ebx.VCAND_Data.TXB1]       ; port address of TXB1
        mov     eax, [ecx]
        out     dx, eax                         ; TXB1...TXB4

        add     ecx, 4                          ; points to fifth data
        mov     dx, [ebx.VCAND_Data.TXB5]       ; port address of TXB1
        mov     eax, [ecx]
        out     dx, eax                         ; TXB5...TXB8

        mov     dx, [ebx.VCAND_Data.COMM_REG]
        mov     ax, 01                          ; transmission request
        out     dx, al

        add     ecx, 8                          ; increment read ptr
        cmp     ecx, [ebx.VCAND_Data.TX_Top]    ; is read ptr at the top ?
        jne     short Send_Message_Exit
        mov     ecx, [ebx.VCAND_Data.TX_Bottom]

Send_Message_Exit:
        mov     [ebx.VCAND_Data.TX_Read], ecx
        clc
        ret

EndProc VCAND_Send_Message



;****************************************************************************
;*                                                                          *
;*  VCAND_Post_Message                                                      *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This function register the VCAND_Post_Message_Now function in the   *
;*      VMM which calls the CAN_Callback function in CAN.DLL.               *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       VCAND_Data                                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Carry clear     :       Success                                     *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Post_Message

        pushad

        bt      [ebx.VCAND_Data.Status], ST_CALLBACK_PENDING
        jc      short Post_Message_Exit_Error

        bt      [ebx.VCAND_Data.Status], ST_POST_MESSAGES
        jnc     short Post_Message_Exit

        bts     [edx.VCAND_Data.Status], ST_CALLBACK_PENDING

        mov     dx, [ebx.VCAND_Data.Message]
        mov     [ebx.VCAND_Data.Msg_To_Send],dx ; this is the msg to send!
        mov     edx, ebx                        ; Node as ref.dat. for callb.

        VMMcall Get_Sys_VM_Handle
        mov     eax, Low_Pri_Device_Boost
        mov     ecx, PEF_Wait_For_STI or PEF_Wait_Not_Crit
        mov     esi, OFFSET32 VCAND_Post_Message_Now
        VMMcall Call_Priority_VM_Event

        jmp     short Post_Message_Exit

Post_Message_Exit_Error:
        bts     [ebx.VCAND_Data.Status], ST_MESSAGE_LOST

Post_Message_Exit:
        popad
        clc
        ret

EndProc VCAND_Post_Message



;****************************************************************************
;*                                                                          *
;*  VCAND_Post_Message_Now                                                  *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This function is called by the VMM. It takes the current            *
;*      message in VCAND_Node data and "sends" it to a windows appl. by     *
;*      calling CAN_Callback in CAN.DLL .                                   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EDX             :       VCAND_Data of calling Node                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Post_Message_Now

        Push_Client_State

        movzx   eax, [VCAND_PostMsg_Seg]        ; is callback addr NULL?
        or      eax, [VCAND_PostMsg_Off32]
        jz      short Post_Message_Now_Exit

        VMMcall Begin_Nest_Exec                 ; prepare to call VM

        ;;  The callback in the CAN.DLL is prototyped as follows:
        ;;  void FAR PASCAL CAN_Callback( WORD ID, WORD wParam )

        xor     eax, eax
        mov     ax, [edx.VCAND_Data.CAN]          ; push CAN ID
        VMMcall Simulate_Push

        xor     eax, eax
        mov     ax, [edx.VCAND_Data.Msg_To_Send]  ; push message type
        VMMcall Simulate_Push

        mov     cx, [VCAND_PostMsg_Seg]         ; CX:EDX -> ...CAN_Callback
        mov     edx, [VCAND_PostMsg_Off32]

        VMMcall Simulate_Far_Call               ; set stuff up for call
        VMMcall Resume_Exec                     ; finally! call it (immediate)

        VMMcall End_Nest_Exec                   ; done with that

Post_Message_Now_Exit:

        Pop_Client_State

        btr     [edx.VCAND_Data.Status], ST_CALLBACK_PENDING
        ret

EndProc VCAND_Post_Message_Now

VxD_LOCKED_CODE_ENDS



;****************************************************************************
;*                              C O D E                                     *
;****************************************************************************

VxD_CODE_SEG

;****************************************************************************
;*                                                                          *
;*  VCAND_Get_Node_By_ID                                                    *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns in EAX and VCAND_Node variable the handle to the node which *
;*      CAN ID is given in EBX. Returns zero and Carry flag set is CAN ID   *
;*      is not valid.                                                       *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID of the node.                         *
;*                                                                          *
;*  EXIT:                                                                   *
;*      VCAND_Node      :       Handle to Node or zero.                     *
;*      EAX             :       Handle to Node or zero.                     *
;*      Carry Flag      :       Set on error.                               *
;*                                                                          *
;*  USES:                                                                   *
;*      EAX, EBX                                                            *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Node_By_ID

        push    ecx
        push    edx

        cmp     bx, [VCAND_Num_Of_Nodes]       ; valid CAN ID number ?
        ja      short Get_Node_ID_Failed

        mov     [VCAND_Node_Ptr], OFFSET32 VCAND_Node1
                                                ; points to Node1 var

Get_Node_ID_Compare:
        mov     edx, [VCAND_Node_Ptr]
        mov     eax, [edx]
        mov     cx, [eax.VCAND_Data.CAN]
        cmp     cx, bx                         ; current CAN = searched CAN ?
        jz      short Get_Node_ID_Success

        add     [VCAND_Node_Ptr], 4            ; get next node
        jmp     short Get_Node_ID_Compare

Get_Node_ID_Failed:
        mov     eax, 0                         ; return zero handle
        stc                                    ; set carry flag - error!
        jmp     short Get_Node_ID_Exit

Get_Node_ID_Success:
        clc                                    ; clear carry flag - success!

Get_Node_ID_Exit:
        mov     [VCAND_Node], eax              ; save handle in VCAND_Node
        pop     edx
        pop     ecx
        ret

EndProc VCAND_Get_Node_By_ID



;****************************************************************************
;*                                                                          *
;*  VCAND_Get_Reg                                                           *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Register specified in EDX                  *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EDX             :       Port address of the Register                *
;*                                                                          *
;*  EXIT:                                                                   *
;*      AX              :       value of the Register                       *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Reg

        xor     ax, ax
        in      al, dx
        ret

EndProc VCAND_Get_Reg



;****************************************************************************
;*                                                                          *
;*  VCAND_Get_Reg_With_Reset                                                *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Register specified in EDX.While requesting *
;*      the value the Controller Chip is switched into its reset mode.      *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      [VCAND_Node]    :       VCAND_Data                                  *
;*      EDX             :       Port address of the Register                *
;*                                                                          *
;*  EXIT:                                                                   *
;*      AX              :       value of the Register                       *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Reg_With_Reset

        push    ebx
        push    edx
        mov     ebx, edx                        ; save Port addres
        mov     eax, [VCAND_Node]

        mov     dx, [eax.VCAND_Data.CONT_REG]
        in      al, dx
        push    eax                             ; save current COMM_REG
        mov     ax, 01h
        out     dx, al                          ; set RESET-REQUEST

        mov     edx, ebx                        ; restore port addres
        xor     ax, ax
        in      al, dx
        mov     bx, ax                          ; save register value

        mov     eax, [VCAND_Node]
        mov     dx, [eax.VCAND_Data.CONT_REG]
        pop     eax
        out     dx, al                          ; restore old COMM_REG

        mov     ax, bx                          ; restore register value
        pop     edx
        pop     ebx
        ret

EndProc VCAND_Get_Reg_With_Reset



;****************************************************************************
;*                                                                          *
;*  VCAND_Set_Reg                                                           *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the new value given in AX to the register given in EDX.         *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      CX              :       New value for the register                  *
;*      EDX             :       Port address of the Register                *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_Reg

        push    eax
        mov     eax, ecx
        out     dx, al                          ; set the new value
        pop     eax
        ret

EndProc VCAND_Set_Reg



;****************************************************************************
;*                                                                          *
;*  VCAND_Set_Reg_With_Reset                                                *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the new value given in AX to the register given in EDX. While   *
;*      setting the value the Controller Chip is switched into its reset    *
;*      mode.                                                               *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      [VCAND_Node]    :       VCAND_Data                                  *
;*      CX              :       New value for the register                  *
;*      EDX             :       Port address of the Register                *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_Reg_With_Reset

        push    ebx
        push    edx
        mov     bx, dx                          ; save Port addres
        mov     eax, [VCAND_Node]

        mov     dx, [eax.VCAND_Data.CONT_REG]
        in      al, dx
        push    eax                             ; save current COMM_REG
        mov     ax, 01h
        out     dx, al                          ; set RESET-REQUEST

        mov     dx, bx                          ; restore Port address
        mov     ax, cx
        out     dx, al                          ; set new value

        mov     eax, [VCAND_Node]
        mov     dx, [eax.VCAND_Data.CONT_REG]
        pop     eax
        out     dx, al                          ; restore old COMM_REG

        mov     ax, bx                          ; restore register value
        pop     edx
        pop     ebx
        ret

EndProc VCAND_Set_Reg_With_Reset



;****************************************************************************
;*                                                                          *
;*  API: VCAND_API_Proc                                                     *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This is the exported API procedure that is callable from VM's.      *
;*      An application needs only to use INT 2Fh, AX=1684h, BX=device ID    *
;*      and a call back address is returned.  Then, when the address is     *
;*      called, eventually it ends up here.                                 *
;*                                                                          *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       VM Handle.                                  *
;*      EBP             :       Client register structure.                  *
;*      Client_CS:IP    :       Instruction following API call.             *
;*      Client_AX       :       Function number.                            *
;*      Client_BX       :       CAN ID                                      *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*              Carry clear     :  success                                  *
;*              Carry set       :  hosed                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_API_Proc

        mov     [VCAND_Cur_VM], ebx            ; save current VM handle
        movzx   eax, [ebp.Client_AX]           ; function #
        movzx   ebx, [ebp.Client_BX]           ; CAN ID in ebx
        movzx   ecx, [ebp.Client_CX]           ; Message ID in ecx

        mov     edx, [VCAND_Max_API]
        cmp     ax, VCAND_Max_API              ; a valid service?
        ja      short VCAND_API_Failed         ; function > VCAND_Max_API
        jmp     VCAND_API_Table[ eax * 4 ]

VCAND_API_Success:

        mov ax, [ebp.Client_AX]
        and     [ebp.Client_EFlags], NOT CF_Mask
        jmp     short VCAND_API_Exit

VCAND_API_Failed:

        mov     [ebp.Client_AX], 0              ; FALSE return value
        or      [ebp.Client_EFlags], CF_Mask

VCAND_API_Exit:
        ret

EndProc VCAND_API_Proc



;****************************************************************************
;*                                                                          *
;*  API: 00h VCAND_Get_Version                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      This service gets the version number of this VxD.  The major        *
;*      version number is loaded into AH; the minor version number is       *
;*      stuffed into AL.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       VM Handle.                                  *
;*      EBP             :       Client register structure.                  *
;*      Client_CS:IP    :       Instruction following API call.             *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*              EAX             :  Major and minor version number.          *
;*              Carry clear     :  Success.                                 *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Version

        mov     [ebp.Client_AX], (VCAND_VERMAJ shl 8) + VCAND_VERMIN
        jmp     VCAND_API_Success

EndProc VCAND_Get_Version



;****************************************************************************
;*                                                                          *
;*  API: 01h VCAND_Set_Filter                                               *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Sets the bit belonging to the Message ID in the buffer belonging to *
;*      CAN ID so that this message is in the filter and will NOT be        *
;*      noticed. It also clears the receive buffer.                         *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID                                      *
;*      ECX             :       Message ID                                  *
;*      EDX             :       1 = set filter and reset RX buffer          *
;*                              everything else = only set filter           *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         EAX          :       1 => Success,  0 => failed                  *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_Filter

        mov     [VCAND_Dummy1], edx             ; save reset buffer info

        cmp     cx, 7FFh                        ; Message ID > 2047 ?
        jg      VCAND_API_Failed

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     ebx, eax
        mov     eax, [ebx.VCAND_Data.Filter]
        bts     [eax], ecx

        mov     ecx, [VCAND_Dummy1]             ; restore reset buffer info
        cmp     ecx, 1                          ; reset RX buffer ?
        jne     short Set_Filter_Exit

        bt      [ebx.VCAND_Data.Status], ST_BUFFER
        jnc     short Set_Filter_Exit
        bt      [ebx.VCAND_Data.Status], ST_IRQ
        jnc     short Set_Filter_Exit

        bts     [ebx.VCAND_Data.Status], ST_FILTER ; set ST_FILTER status

        mov     eax, [ebx.VCAND_Data.IRQ_Handle]
        VxDCall VPICD_Physically_Mask           ; disable IRQ

        mov     [ebx.VCAND_Data.Num_RX], 0      ; reset RX_Num
        mov     edx, [ebx.VCAND_Data.RX_Bottom]
        mov     [ebx.VCAND_Data.RX_Write], edx
        mov     [ebx.VCAND_Data.RX_LastMsg], edx

        VxDCall VPICD_Physically_Unmask         ; enable IRQ

Set_Filter_Exit:
        jmp     VCAND_API_Success

EndProc VCAND_Set_Filter



;****************************************************************************
;*                                                                          *
;*  API: 02h VCAND_Get_Filter                                               *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Checks, if the bit belonging to the Message ID in the filter buffer *
;*      belonging to CAN ID is set or not. So it checks, if this messages   *
;*      is in the filter or not. Returns Client_AX = 1 if the Message ID is *
;*      in the filter and Client_AX = 0 if not.                             *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID                                      *
;*      ECX             :       Message ID                                  *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       0 = Msg not in filter,  1 = Msg in filter   *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Filter

        cmp     cx, 7FFh                        ; Message ID > 2047 ?
        jg      VCAND_API_Failed

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     ebx, eax
        mov     eax, [ebx.VCAND_Data.Filter]
        bt      [eax], ecx
        jc      short Get_Filter_Found          ; it is !

        mov     [ebp.Client_AX], 0              ; Message NOT in Filter
        jmp     short Get_Filter_Exit

Get_Filter_Found:
        mov     [ebp.Client_AX], 1              ; Message in Filter

Get_Filter_Exit:
        jmp     VCAND_API_Success

EndProc VCAND_Get_Filter



;****************************************************************************
;*                                                                          *
;*  API: 03h VCAND_Reset_Filter                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Reset the filter buffer of CAN ID so that all messages will be      *
;*      noticed and clears the receive buffer.                              *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID                                      *
;*      ECX             :       Message ID to be resetted.                  *
;*                              2048 = reset complete filter.               *
;*      EDX             :       1 = reset filter and reset RX buffer        *
;*                              everything else = only reset filter         *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         EAX          :       1 => Success,  0 => failed                  *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Reset_Filter

        mov     [VCAND_Dummy1], edx             ; save reset buffer info

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed
        mov     edx, eax

        mov     ebx, [edx.VCAND_Data.Filter]    ; pointer to filter in ebx
        cmp     cx, 2048
        je      short Reset_Filter_Complete

Reset_Filter_Single:
        btr     [ebx], ecx                      ; reset single message
        jmp     short Reset_Filter_Check

Reset_Filter_Complete:                          ; reset complete filter
        mov     eax, [VCAND_Filter_Size]
        mov     ecx, 0                          ; fill data
Fill_Data:
        mov     [ebx], ecx                      ; "0" in buffer
        inc     ebx                             ; next byte in buffer
        dec     eax                             ; buffer full ?
        jnz     short Fill_Data

Reset_Filter_Check:
        mov     ecx, [VCAND_Dummy1]             ; restore reset buffer info
        cmp     ecx, 1                          ; reset RX buffer ?
        jne     short Reset_Filter_Exit

        bt      [edx.VCAND_Data.Status], ST_BUFFER  ; Buffers allocated ?
        jnc     short Reset_Filter_Exit
        bt      [edx.VCAND_Data.Status], ST_IRQ     ; IRQ enabled ?
        jnc     short Reset_Filter_Exit

        mov     eax, [edx.VCAND_Data.IRQ_Handle]
        VxDCall VPICD_Physically_Mask           ; disable IRQ

        mov     [edx.VCAND_Data.Num_RX], 0      ; reset RX_Num
        mov     ebx, [edx.VCAND_Data.RX_Bottom]
        mov     [edx.VCAND_Data.RX_Write], ebx
        mov     [edx.VCAND_Data.RX_LastMsg], ebx

        VxDCall VPICD_Physically_Unmask         ; enable IRQ

Reset_Filter_Exit:
        jmp     VCAND_API_Success

EndProc VCAND_Reset_Filter



;****************************************************************************
;*                                                                          *
;*  API: 04h VCAND_Set_CONT_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Control Register in the 80C200 controller chip.             *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Control Register          *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_CONT_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.CONT_REG]   ; get port address
        call    VCAND_Set_Reg                   ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_CONT_REG



;****************************************************************************
;*                                                                          *
;*  API: 05h VCAND_Set_COMM_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Command Register in the 80C200 controller chip.             *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Command Register          *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_COMM_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.COMM_REG]   ; get port address
        call    VCAND_Set_Reg                   ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_COMM_REG



;****************************************************************************
;*                                                                          *
;*  API: 06h VCAND_Set_ACC_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Acceptance Code Register in the 80C200 controller chip.     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Acceptance Code Register  *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_ACC_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.ACC_REG]    ; get port address
        call    VCAND_Set_Reg_With_Reset        ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_ACC_REG



;****************************************************************************
;*                                                                          *
;*  API: 07h VCAND_Set_ACM_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Acceptance Mask Register in the 80C200 controller chip.     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Acceptance Mask Register  *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_ACM_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.ACM_REG]    ; get port address
        call    VCAND_Set_Reg_With_Reset        ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_ACM_REG



;****************************************************************************
;*                                                                          *
;*  API: 08h VCAND_Set_BT0_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Bus Timing Register 0 in the 80C200 controller chip. This   *
;*      function should be used together witch VCAND_Set_BT1_REG to set a   *
;*      new Bitrate per second.                                             *
;*                                                                          *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for BTR0                          *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_BT0_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.BT0_REG]    ; get port address
        call    VCAND_Set_Reg_With_Reset        ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_BT0_REG



;****************************************************************************
;*                                                                          *
;*  API: 09h VCAND_Set_BT1_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Bus Timing Register 1 in the 80C200 controller chip. This   *
;*      function should be used together witch VCAND_Set_BT0_REG to set a   *
;*      new Bitrate per second.                                             *
;*                                                                          *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for BTR1                          *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_BT1_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.BT1_REG]    ; get port address
        call    VCAND_Set_Reg_With_Reset        ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_BT1_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Ah VCAND_Set_OUTP_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Output Control Register in the 80C200 controller chip.      *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Output Control Register   *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_OUTP_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.OUTP_REG]   ; get port address
        call    VCAND_Set_Reg_With_Reset        ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_OUTP_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Bh VCAND_Set_CLKD_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Set the Clock Divider Register in the 80C200 controller chip.       *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       new value for the Clock Divider Register    *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Set_CLKD_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.CLKD_REG]   ; get port address
        call    VCAND_Set_Reg                   ; set new value to register

        jmp     VCAND_API_Success

EndProc VCAND_Set_CLKD_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Ch VCAND_Get_CONT_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Control Register in the 80C200             *
;*      controller chip.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Control Register               *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_CONT_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.CONT_REG]   ; get port address
        call    VCAND_Get_Reg                   ; get register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_CONT_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Dh VCAND_Get_STAT_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Status Register in the 80C200              *
;*      controller chip.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Status Register                *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_STAT_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.STAT_REG]   ; get port address
        call    VCAND_Get_Reg                   ; get register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_STAT_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Eh VCAND_Get_INT_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Interrupt Register in the 80C200           *
;*      controller chip.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Interrupt Register             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_INT_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.INT_REG]    ; get port address
        call    VCAND_Get_Reg                   ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_INT_REG



;****************************************************************************
;*                                                                          *
;*  API: 0Fh VCAND_Get_ACC_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Acceptance Code Register in the 80C200     *
;*      controller chip.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Acceptance Code Register       *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_ACC_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.ACC_REG]    ; get port address
        call    VCAND_Get_Reg_With_Reset        ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_ACC_REG



;****************************************************************************
;*                                                                          *
;*  API: 10h VCAND_Get_ACM_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Acceptance Mask Register in the 80C200     *
;*      controller chip. To do this the chip is switched into reset mode.   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Acceptance Mask Register       *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_ACM_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.ACM_REG]    ; get port address
        call    VCAND_Get_Reg_With_Reset        ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_ACM_REG



;****************************************************************************
;*                                                                          *
;*  API: 11h VCAND_Get_BT0_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Bus Timing 0 Register in the 80C200        *
;*      controller chip. To do this the chip is switched into reset mode.   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Bus Timing 0 Register          *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_BT0_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.BT0_REG]    ; get port address
        call    VCAND_Get_Reg_With_Reset        ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_BT0_REG



;****************************************************************************
;*                                                                          *
;*  API: 12h VCAND_Get_BT1_REG                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Bus Timing 1 Register in the 80C200        *
;*      controller chip. To do this the chip is switched into reset mode.   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Bus Timing 1 Register          *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_BT1_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.BT1_REG]    ; get port address
        call    VCAND_Get_Reg_With_Reset        ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_BT1_REG



;****************************************************************************
;*                                                                          *
;*  API: 13h VCAND_Get_OUTP_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Output Control Register in the 80C200      *
;*      controller chip. To do this the chip is switched into reset mode.   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Output Control Register        *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_OUTP_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.OUTP_REG]   ; get port address
        call    VCAND_Get_Reg_With_Reset        ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_OUTP_REG



;****************************************************************************
;*                                                                          *
;*  API: 14h VCAND_Get_CLKD_REG                                             *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the value of the Clock Divider Register in the 80C200       *
;*      controller chip.                                                    *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       value of the Clock Divider Register         *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_CLKD_REG

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     dx, [eax.VCAND_Data.CLKD_REG]   ; get port address
        call    VCAND_Get_Reg                   ; get the register value
        mov     [ebp.Client_AX], ax             ; return value in AX

        jmp     VCAND_API_Success

EndProc VCAND_Get_CLKD_REG



;****************************************************************************
;*                                                                          *
;*  API: 15h VCAND_Get_Counter                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Return the actual values of all internal counters                   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       Received Counter                            *
;*         BX           :       Transmit Counter                            *
;*         CX           :       Error Counter                               *
;*         DX           :       Overrun Counter                             *
;*         SI           :       Wake Up Counter                             *
;*         DI           :       Filtered Counter                            *
;*                                                                          *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Counter

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     ebx, [eax.VCAND_Data.Num_RX]
        mov     [ebp.Client_AX], bx
        mov     ebx, [eax.VCAND_Data.Num_TX]
        mov     [ebp.Client_BX], bx
        mov     ebx, [eax.VCAND_Data.Num_Error]
        mov     [ebp.Client_CX], bx
        mov     ebx, [eax.VCAND_Data.Num_Overrun]
        mov     [ebp.Client_DX], bx
        mov     ebx, [eax.VCAND_Data.Num_Wake_Up]
        mov     [ebp.Client_SI], bx
        mov     ebx, [eax.VCAND_Data.Num_Filtered]
        mov     [ebp.Client_DI], bx

        jmp     VCAND_API_Success

EndProc VCAND_Get_Counter



;****************************************************************************
;*                                                                          *
;*  API: 16h VCAND_Reset_Counter                                            *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Reset all or one specific counter.                                  *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      ECX             :       0 - reset all Counters                      *
;*                              1 - reset Num_Error                         *
;*                              2 - reset Num_Overrun                       *
;*                              3 - reset Num_Wake_Up                       *
;*                              4 - reset Num_Filtered                      *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Reset_Counter

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        cmp     cx, 0
        jz      short Reset_Counter_All
        cmp     cx, 1
        jz      short Reset_Counter_Error
        cmp     cx, 2
        jz      short Reset_Counter_Overrun
        cmp     cx, 3
        jz      short Reset_Counter_Wake_Up
        cmp     cx, 4
        jz      short Reset_Counter_Filtered

        jmp     VCAND_API_Failed

Reset_Counter_All:
        mov     [eax.VCAND_Data.Num_Error], 0
        mov     [eax.VCAND_Data.Num_Overrun], 0
        mov     [eax.VCAND_Data.Num_Wake_Up], 0
        mov     [eax.VCAND_Data.Num_Filtered], 0
        jmp     short Reset_Counter_Exit

Reset_Counter_Error:
        mov     [eax.VCAND_Data.Num_Error], 0
        jmp     short Reset_Counter_Exit

Reset_Counter_Overrun:
        mov     [eax.VCAND_Data.Num_Overrun], 0
        jmp     short Reset_Counter_Exit

Reset_Counter_Wake_Up:
        mov     [eax.VCAND_Data.Num_Wake_Up], 0
        jmp     short Reset_Counter_Exit

Reset_Counter_Filtered:
        mov     [eax.VCAND_Data.Num_Filtered], 0


Reset_Counter_Exit:
        jmp     VCAND_API_Success

EndProc VCAND_Reset_Counter



;****************************************************************************
;*                                                                          *
;*  API: 17h VCAND_Allocate_Buffer                                          *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Allocates the memory for the send and receive buffer and init the   *
;*      pointer RX_xxx and TX_xxx.                                          *
;*      Usually this function is called while an application opens the      *
;*      CAN driver. The function checks, if the ST_INIT bit, the ST_BUFFER  *
;*      bit and the ST_IRQ bit in the Status variable is set. This          *
;*      function must be called BEFORE unmasking the IRQ.                   *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Allocate_Buffer

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed
        mov     ebx, eax

        bt      [ebx.VCAND_Data.Status], ST_INIT   ; INIT status ?
        jnc     VCAND_API_Failed

        bt      [ebx.VCAND_Data.Status], ST_BUFFER ; BUFFER status ?
        jc      VCAND_API_Failed

        bt      [ebx.VCAND_Data.Status], ST_IRQ    ; IRQ status ?
        jc      VCAND_API_Failed

        xor     ecx, ecx
        xor     edx, edx
        mov     eax, [ebx.VCAND_Data.BufSize]
        mov     ecx, [VCAND_Message_Size]
        mul     ecx                             ; calculating buffer size
        push    eax                             ; save size of 1 buffer
        mov     ecx, 2
        mul     ecx
        jc      short Allocate_Buffer_Error2
        jz      short Allocate_Buffer_Error2
        mov     ecx, eax                        ; size of 2 buffers in ecx

        VMMCall _HeapAllocate, 
        cmp     eax, 0
        jz      short Allocate_Buffer_Error2
        mov     ebx, eax                        ; save base pointer in ebx
        shr     eax, 12
        VMMCall _LinPageLock, 
        cmp     eax, 0
        jz      short Allocate_Buffer_Error1

        pop     edx                             ; restore size of 1 buffeer
        mov     eax, ebx                        ; restore base pointer
        mov     ebx, [VCAND_Node]
        mov     [ebx.VCAND_Data.RX_Bottom], eax ; RX_Bottom
        mov     [ebx.VCAND_Data.RX_Write], eax  ; RX_Write
        mov     [ebx.VCAND_Data.RX_LastMsg],eax ; RX_LastMsg
        add     eax, edx
        mov     [ebx.VCAND_Data.RX_Top], eax    ; RX_Top

        mov     [ebx.VCAND_Data.TX_Bottom], eax ; TX_Bottom
        mov     [ebx.VCAND_Data.TX_Read], eax   ; TX_Read
        mov     [ebx.VCAND_Data.TX_LastMsg],eax ; TX_LastMsg
        add     eax, edx
        mov     [ebx.VCAND_Data.TX_Top], eax    ; TX_Top

        jmp     short Allocate_Buffer_Exit

Allocate_Buffer_Error1:
        VMMCall _HeapFree,              ; free memory

Allocate_Buffer_Error2:
        mov     [ebx.VCAND_Data.RX_Bottom], 0   ; clear pointers
        mov     [ebx.VCAND_Data.RX_Top], 0
        mov     [ebx.VCAND_Data.RX_Write], 0
        mov     [ebx.VCAND_Data.RX_LastMsg], 0
        mov     [ebx.VCAND_Data.TX_Bottom], 0
        mov     [ebx.VCAND_Data.TX_Top], 0
        mov     [ebx.VCAND_Data.TX_Read], 0
        mov     [ebx.VCAND_Data.TX_LastMsg], 0
        btr     [ebx.VCAND_Data.Status], ST_BUFFER ; reset BUFFER status
        jmp     VCAND_API_Failed

Allocate_Buffer_Exit:
        mov     [ebx.VCAND_Data.Num_RX], 0      ; empty receive buffer
        mov     [ebx.VCAND_Data.Num_TX], 0      ; empty transmit buffer
        bts     [ebx.VCAND_Data.Status], ST_BUFFER ; set BUFFER status
        jmp     VCAND_API_Success

EndProc VCAND_Allocate_Buffer



;****************************************************************************
;*                                                                          *
;*  API: 18h VCAND_Free_Buffer                                              *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Free the memory of send and receive buffer and set the RX_xxx and   *
;*      TX_xxx pointer to zero. Usually this function is called while an    *
;*      application opens the CAN driver. This function checks if the       *
;*      ST_INIT bit, the ST_BUFFER bit and the ST_IRQ bit in the Status     *
;*      variable is set. This function can only be called AFTER masking     *
;*      the interrupt !                                                     *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Free_Buffer

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed
        mov     ebx, eax

        bt      [ebx.VCAND_Data.Status], ST_INIT   ; INIT status ?
        jnc     VCAND_API_Failed

        bt      [ebx.VCAND_Data.Status], ST_BUFFER ; BUFFER status ?
        jnc     VCAND_API_Failed

        bt      [ebx.VCAND_Data.Status], ST_IRQ    ; IRQ status ?
        jc      VCAND_API_Failed

        mov     eax, [ebx.VCAND_Data.RX_Bottom] ; base pointer to buffers
        VMMCall _HeapFree,              ; free both buffers
        cmp     eax, 0
        jz      VCAND_API_Failed

        mov     [ebx.VCAND_Data.RX_Bottom], 0   ; clear pointers
        mov     [ebx.VCAND_Data.RX_Top], 0
        mov     [ebx.VCAND_Data.RX_Write], 0
        mov     [ebx.VCAND_Data.RX_LastMsg], 0
        mov     [ebx.VCAND_Data.TX_Bottom], 0
        mov     [ebx.VCAND_Data.TX_Top], 0
        mov     [ebx.VCAND_Data.TX_Read], 0
        mov     [ebx.VCAND_Data.TX_LastMsg], 0
        btr     [ebx.VCAND_Data.Status], ST_BUFFER ; reset BUFFER status

        jmp     VCAND_API_Success

EndProc VCAND_Free_Buffer



;****************************************************************************
;*                                                                          *
;*  API: 19h VCAND_Mask_IRQ                                                 *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Mask physically the interrupt for the given CAN ID.                 *
;*      Usually this function is called while an application closes the     *
;*      CAN driver. To mask an IRQ the ST_INIT bit and the ST_BUFFER bit    *
;*      in the Status variable must be set.                                 *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Mask_IRQ

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        bt      [eax.VCAND_Data.Status], ST_INIT   ; INIT status ?
        jnc     VCAND_API_Failed

        bt      [eax.VCAND_Data.Status], ST_BUFFER ; BUFFER status ?
        jnc     VCAND_API_Failed

        btr     [eax.VCAND_Data.Status], ST_IRQ    ; reset IRQ status

        mov     ebx, [eax.VCAND_Data.IRQ_Handle]
        mov     eax, ebx
        VxDCall VPICD_Physically_Mask

        jmp     VCAND_API_Success

EndProc VCAND_Mask_IRQ



;****************************************************************************
;*                                                                          *
;*  API: 1Ah VCAND_Unmask_IRQ                                               *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Unmask physically the interrupt for the given CAN ID.               *
;*      Usually this function is called while an application opens the      *
;*      CAN driver. To unmask an IRQ the ST_INIT bit and the ST_BUFFER bit  *
;*      in the Status variable must be set.                                 *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Unmask_IRQ

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed
        mov     ebx, eax

        bt      [ebx.VCAND_Data.Status], ST_INIT   ; INIT status ?
        jnc     VCAND_API_Failed

        bt      [ebx.VCAND_Data.Status], ST_BUFFER ; BUFFER status ?
        jnc     VCAND_API_Failed

        bts     [ebx.VCAND_Data.Status], ST_IRQ    ; set IRQ status

        VMMCall Get_System_Time
        mov     [ebx.VCAND_Data.Time_Base], eax

        mov     eax, [ebx.VCAND_Data.IRQ_Handle]
        VxDCall VPICD_Physically_Unmask

        jmp     VCAND_API_Success

EndProc VCAND_Unmask_IRQ



;****************************************************************************
;*                                                                          *
;*  API: 1Bh VCAND_Get_Status                                               *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Returns the actual value of the status word of the driver.          *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         AX           :       actual status of CAN (ID) driver            *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Get_Status

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed

        mov     bx, [eax.VCAND_Data.Status]     ; actual status word
        mov     [ebp.Client_AX], bx             ; return status in ax

        jmp     VCAND_API_Success

EndProc VCAND_Get_Status



;****************************************************************************
;*                                                                          *
;*  API: 1Ch VCAND_Reset                                                    *
;*                                                                          *
;*  DESCRIPTION:                                                            *
;*      Unmask IRQ, free all buffers, reset counters, reset status word     *
;*      (accept ST_INIT and ST_ERROR), reset controller, reset all window   *
;*      handles (HWND).                                                     *
;*                                                                          *
;*      This function does *NOT* reset the message filter !                 *
;*                                                                          *
;*  ENTRY:                                                                  *
;*      EBX             :       CAN ID;                                     *
;*      EBP             :       Client register structure.                  *
;*                                                                          *
;*  EXIT:                                                                   *
;*      Client:                                                             *
;*         Carry clear  :       Success.                                    *
;*                                                                          *
;****************************************************************************

BeginProc VCAND_Reset

        call    VCAND_Get_Node_By_ID            ; node handle in eax
        jc      VCAND_API_Failed
        mov     ebx, eax

Reset_IRQ:
        bt      [ebx.VCAND_Data.Status], ST_IRQ
        jnc     short Reset_Buffer
        mov     eax, [ebx.VCAND_Data.IRQ_Handle]
        VxDCall VPICD_Physically_Mask