PAGE ,132
title VxD2B.ASM - Example Device Driver #2b
;EM	VxD2B - Example Device Driver #2b
;
;	Copyright 1992, Cherry Hill Software
;	All rights reserved.
;
;	SUMMARY
;	    This driver simulates an interrupting device.  The control
;	    port (output) has the following bit assignments:
;
;		Bit 0 - Start I/O.  Writing a zero to this bit begins
;			I/O transfer.  The "transfer" takes approximately
;			one-tenth of a second.	Writing a one to this
;			bit has no effect.
;
;		Bit 1 - Send EOI to device.  Writing a zero to this bit
;			sends End-of-Interrupt to the device and removes
;			any pending interrupt request.	Writing a one to
;			this bit has no effect.
;
;		All other bits: Always must write ones for future
;				compatibility.
;
;	    When reading the port, the following is returned:
;
;		Bit 0 - initially set, this is reset when output port bit
;			1 is reset and is set when the interrupt request
;			is asserted.  This bit is zero when the device
;			is transferring data and is set to indicate
;			transfer complete.
;
;		Bit 1 - initially set, this is reset when the interrupt
;			request is asserted and is reset when the device
;			removes the interrupt request.	This bit is zero
;			to indicate a pending interrupt and is set if
;			no interrupt is pending.
;
;		All other bits: ignore returned value for future
;				compatibility.
;
;	WARNINGS
;
;
	.386p


.xlist
include vmm.inc
include debug.inc
include v86mmgr.inc
include vpicd.inc
include ..\include\bogus.inc
.list

VM_Not_Executable equ VM_Not_Executeable ; acckk!

subttl	VxD Declaration/Definition
page

VxD2B_Init_Order equ VNETBIOS_Init_Order+100 ; Do this after the Virtual net
VxD2B_Device_ID equ Bogus_Device_ID


Declare_Virtual_Device VXD2, 1, 0, VxD2B_Control, VxD2B_Device_ID, \
		       VxD2B_Init_Order


VxD_DATA_SEG

;
;   Virtual Interrupt Descriptor Structure
;
;   We pass this to VPIDC_Virtualize_IRQ.  Here we specify the
;   interrupt level, the hardware interrupt procedure, and the procedures
;   that VPICD calls when the interrupt is dispatched into the VM and
;   when the VM returns from the interrupt.
;
IRQD VPICD_IRQ_Descriptor <FAKE_IRQ,,,OFFSET32 VxD2_VInt_Proc,\
			   ,\
			   OFFSET32 VxD2_Mask_Change_Proc,\
			   OFFSET32 VxD2_IRET_Proc>

hIRQ	    dd	-1	    ; IRQ handle
hOwner	    dd	-1	    ; Owning VM handle
hTimeout    dd	0	    ; handle to timeout callback (0=>none)
bFakeData   db	01111111b   ; Fake I/O port data

VxD_DATA_ENDS



subttl Dispatch VxD Control
page
VxD_LOCKED_CODE_SEG

BeginProc CheckOwner, NO_LOG
	cmp	ebx,hOwner
	jne	short co1
	ret			    ; exit if owner is calling
co1:
	cmp	hOwner,-1
	jne	short co2	    ; skip if non-owner calling
	mov	hOwner,ebx	    ; set the owner
	ret
co2:
	mov	al,-1
	ret
EndProc CheckOwner


BeginProc TimeoutProc
	mov	hTimeout,0	    ; clear the handle
	cmp	edx,hOwner	    ; Still the same owner?
	jne	short to1	    ; skip if not
	test	bFakeData,FAKE_STAT_BUSY    ; I/O pending?
	jnz	short to1	    ; skip if not
	cmp	hOwner,-1	    ; Do we have an owner?
	je	short to1	    ; skip if not
	mov	eax,hIRQ
	mov	ebx,hOwner
	VxDcall VPICD_Set_Int_Request	; assert the interrupt
	mov	al,bFakeData
	and	al,NOT (FAKE_STAT_IRQ)	; indicate so in status port
	or	al,FAKE_STAT_BUSY	; indicate no longer busy
	mov	bFakeData,al
to1:
	ret
EndProc TimeoutProc


;IP	Port_IO_Callback - Process access to FAKE_PORT
;
;	ENTRY
;	    EAX - The output value (for output instructions)
;	    EBX - The handle to the current VM
;	    ECX - The type of I/O operation
;	    DS,ES - FLAT
;
;	EXIT
;	    EAX the input value (for input instructions)
;
;	WARNINGS
;
;	NOTES
;	    Note that we don't even look at the client register frame.
;
;	    We simply read and increment
;
;	CALLS
;
BeginProc Port_IO_Callback, NO_LOG
	Dispatch_Byte_IO Fall_Through,Port_Output_Callback

Port_Input_Callback:
	call	CheckOwner
	jc	short ioexit
	mov	al,bFakeData
	or	bFakeData,FAKE_STAT_ERROR   ; clear pending error
ioexit:
	ret

Port_Output_Callback:
	call	CheckOwner
	jc	short ioexit		; ignore I/O if not the owner
	test	al,FAKE_CTL_START
	jnz	short poc1		; skip if not starting I/O
	test	bFakeData,FAKE_STAT_BUSY
	jz	short poc1		; skip if already busy
	test	bFakeData,FAKE_STAT_IRQ
	jz	short poc1		; skip if IRQ pending
	push	eax
	push	edx
	and	bFakeData,NOT (FAKE_STAT_ERROR) ; presume error
	mov	eax,100 		; callback in 1/10 second
	mov	edx,hOwner		; pass the owner to the callback
	mov	esi,OFFSET32 TimeoutProc
	VMMcall Set_VM_Time_Out
	pop	edx
	pop	eax
	or	esi,esi
	jz	short poc1		; skip if error
	and	bFakeData,NOT (FAKE_STAT_BUSY)	; indicate busy
	or	bFakeData,FAKE_STAT_ERROR   ; else, clear error indication
	mov	hTimeout,esi		; save timeout handle
poc1:
	test	al,FAKE_CTL_EOI
	jnz	short poc2		; skip if not sending EOI
	test	bFakeData,FAKE_STAT_IRQ ; interrupt pending?
	jnz	short poc2		; skip if not
	or	bFakeData,FAKE_STAT_IRQ ; indicate interrupt no longer pending
	push	eax
	mov	eax,hIRQ
	VxDcall VPICD_Clear_Int_Request
	pop	eax
poc2:
	ret
EndProc Port_IO_Callback


; ECX == 0 if unmasking (enabling), ECX != 0 if masking (disabling).
BeginProc VxD2_Mask_Change_Proc
	call	CheckOwner
	jc	short mcp9		; ignore if not the owner
	jcxz	mcp9			; skip if unmasking (enabling)
;
; The owner is relinquishing control.  Allow another VM to sign up.
;
	mov	hOwner,-1		; clear the owner

mcp9:
	ret
EndProc VxD2_Mask_Change_Proc


; called when the ISR executes
BeginProc VxD2_VInt_Proc
	mov	eax,High_Pri_Device_Boost
	VMMCall Adjust_Exec_Priority	    ; boost priority for int processing
	ret
EndProc VxD2_VInt_Proc


; called when the ISR returns (IRETs)
BeginProc VxD2_IRET_Proc
	mov	eax,-(High_Pri_Device_Boost)
	VMMCall Adjust_Exec_Priority	    ; restore priority
	ret
EndProc VxD2_IRET_Proc


ifdef DEBUG
BeginProc VxD2B_Debug_Query
	Trace_Out   "VxD2 has no debug command support."
	clc
	ret
EndProc VxD2B_Debug_Query
endif


;
;   VxD2B_Control
;

CtlDisp macro x
 Control_Dispatch x, VxD2B_&x
 endm

Begin_Control_Dispatch VxD2B
	CtlDisp Device_Init
ifdef DEBUG
	CtlDisp Debug_Query
endif
End_Control_Dispatch VxD2B

VxD_LOCKED_CODE_ENDS


VxD_CODE_SEG
VxD_CODE_ENDS


subttl	Initialization Data
page
VxD_IDATA_SEG
; put initialization-only data here
VxD_IDATA_ENDS



subttl	VxD Initialization
page
VxD_ICODE_SEG

page
;EP	VxD2B_Device_Init - Non-critical Device Initialization
;
;	ENTRY
;	    EBP - Client frame
;	    EBX - System VM handle
;	    DS,ES - FLAT
;
;	EXIT
;	    SUCCESS
;		Carry clear
;	    FAILURE
;		Carry set
;
;	WARNINGS
;
;	NOTES
;
;	CALLS
;

BeginProc VxD2B_Device_Init
	Debug_Out "VxD2B_Device_Init"

	mov	edi,OFFSET32 IRQD
	VxDcall VPICD_Virtualize_IRQ	; Virtualize the interrupt
	jc	short vdi1		; exit if error
	mov	hIRQ,eax		; save the handle

	mov	edx,FAKE_PORT
	mov	esi,OFFSET32 Port_IO_Callback
	VMMCall Install_IO_Handler
	VMMCall Enable_Global_Trapping	;

	clc				; No error
vdi1:
	ret
EndProc VxD2B_Device_Init



VxD_ICODE_ENDS


VxD_REAL_INIT_SEG

VxD2B_Real_Init LABEL FAR ; Called before Windows enters protected mode
	mov ax,Device_Load_Ok	; Allow the VxD to load
	xor bx,bx		; No EMM Exclude pages
	xor si,si		; no instance data items
				; pass edx unmodified
	ret

VxD_REAL_INIT_ENDS

	END VxD2B_Real_Init
