impulsetracker/VSound/VXD/VSOUND.ASM

680 lines
17 KiB
NASM

PAGE 58,132
.386p
;
; Client has:
; States -> state is set by writing to port
; data is retrieved by reading from port
;
; State 0: Get Identification "ITVXDDRV"
; State 1: Get Server string (64 bytes)
; State 2: Get buffer used
; State 3: Reset Client
; State 4: Get debug value
; State 5: Get TSC
;
;
; Server interface:
; Write 0 to reset
; If read, returns "ITSERVER", else 01h if Server has been validated.
; Needs to receive "ITSERVER" to validate.
; If validated, receives server string of max 64 bytes, no 0 permitted.
;
.XLIST
INCLUDE VMM.Inc
INCLUDE Debug.Inc
INCLUDE Shell.inc
.LIST
VSound_Client_Address EQU 400h
VSound_Server_Address EQU 401h
VSound_Data_Address EQU 402h
VSOUND_CLIENTSTATES EQU 7
VSOUND_BUFFERSIZE EQU (64*1024)
;******************************************************************************
; 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 VSOUND, 1, 0, VSOUND_Control, Undefined_Device_ID ,,,
;******************************************************************************
; L O C A L D A T A
;******************************************************************************
VxD_LOCKED_DATA_SEG
VSound_Data DB VSOUND_BUFFERSIZE Dup (0)
VSound_HeadPointer DD 0
VSound_TailPointer DD 0
VSound_Client DD 0
VSound_Server DD 0
VSound_ClientCallback DD 0
VSound_ID DB "ITVXDDRV"
VSound_State DD 0
VSound_BufferUsed DD 0
VSound_StatePos DD 0
VSound_ServerID DB "ITSERVER"
VSound_ServerInPos DD 0
VSound_ServerOutPos DD 0
VSound_ServerValid DD 0
VSound_DebugValue DD 0
VSound_TimeStamp1 DD 0
VSound_TimeStamp2 DD 0
VSound_InTable DD Offset32 VSound_Identification
DD Offset32 VSound_GetServerString
DD Offset32 VSound_GetBufferUsed
DD Offset32 VSound_GetDebugValue
DD Offset32 VSound_Get0
DD Offset32 VSound_GetDebugValue
DD Offset32 VSound_GetTSC
VSound_OutTable DD Offset32 VSound_Out_ResetStatePos
DD Offset32 VSound_Out_ResetStatePos
DD Offset32 VSound_Out_GetBufferUsed
DD Offset32 VSound_Out_ResetClient
DD Offset32 VSound_Out_SetCallbackAddress
DD Offset32 VSound_Out_ResetStatePos
DD Offset32 VSound_Out_GetTSC
VSound_ServerString DB 64 Dup (0)
VxD_LOCKED_DATA_ENDS
;******************************************************************************
; I N I T I A L I Z A T I O N C O D E
;******************************************************************************
VxD_IDATA_SEG
Begin_Vxd_IO_Table IO_Table
Vxd_IO VSound_Client_Address, VSound_Client_Hook
Vxd_IO VSound_Server_Address, VSound_Server_Hook
Vxd_IO VSound_Data_Address, VSound_Data_Hook
End_Vxd_IO_Table IO_Table
VxD_IDATA_ENDS
VxD_ICODE_SEG
;******************************************************************************
;
; VSOUND_Device_Init
;
; DESCRIPTION:
;
; This routine is called during Windows startup. It needs to
; install the I/O handler for our device, and set up the system
; VM as the default owner.
;
;
;==============================================================================
BeginProc VSOUND_Device_Init
Xor EAX, EAX
Mov VSound_Client, EAX ; no current owner
Mov VSound_Server, EAX ; no current owner
Mov VSound_ClientCallback, EAX ; No callback
Mov EDI, OFFSET32 IO_Table
VMMCall Install_Mult_IO_Handlers
Ret
EndProc VSOUND_Device_Init
VxD_ICODE_ENDS
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VxD_CODE_SEG
;******************************************************************************
;
; VSOUND_Destroy_VM
;
; DESCRIPTION:
;
; This routine is called when a VM is destroyed. We need to check
; to see if the VM in question is the current owner of the device.
;
;==============================================================================
BeginProc VSOUND_Destroy_VM
Xor EAX, EAX
Cmp EBX, VSound_Client ; Destroying device owner?
JNE Short VDM_Client
Mov VSound_Client, EAX
Mov VSound_ClientCallback, EAX
VDM_Client:
Cmp EBX, VSound_Server
JNE VDM_Server
Mov VSound_Server, EAX
Mov VSound_ServerValid, EAX
VDM_Server:
ClC
Ret
EndProc VSOUND_Destroy_VM
VxD_CODE_ENDS
;******************************************************************************
VxD_LOCKED_CODE_SEG
;******************************************************************************
;
; VSound_Control
;
; DESCRIPTION:
;
; This is a call-back routine to handle the messages that are sent
; to VxD's to control system operation.
;
;==============================================================================
BeginProc VSound_Control
Control_Dispatch Device_Init, VSound_Device_Init
Control_Dispatch Destroy_VM, VSound_Destroy_VM
ClC
Ret
EndProc VSound_Control
VxD_LOCKED_CODE_ENDS
VxD_CODE_SEG
;*****************************************************************************
;
; VSound_Client_Hook
;
; DESCRIPTION:
;
; This routine is called for every I/O access to our port. First,
; it checks to see if the VM issuing the I/O is the current owner.
; If not, it displays a dialog box so the user can decide what to
; do.
;
;*****************************************************************************
VSound_Identification:
Pop EAX
Push ECX
Mov ECX, VSound_StatePos
Mov AL, [VSound_ID+ECX]
Inc ECX
And ECX, 7
Mov VSound_StatePos, ECX
Pop ECX
Ret
VSound_GetServerString:
Pop EAX
Push ECX
Mov ECX, VSound_StatePos
Mov AL, [VSound_ServerString+ECX]
Inc ECX
And ECX, 63
Mov VSound_StatePos, ECX
Pop ECX
Ret
VSound_GetBufferUsed:
Pop EAX
Push ECX
Mov ECX, VSound_StatePos
Xor ECX, 1
Mov AL, [Byte Ptr VSound_BufferUsed+ECX]
Mov VSound_StatePos, ECX
Pop ECX
Ret
VSound_GetTSC:
Pop EAX
Push ECX
Mov ECX, VSound_StatePos
Mov AL, [Byte Ptr VSound_TimeStamp1+ECX]
Inc ECX
And ECX, 7
Mov VSound_StatePos, ECX
Pop ECX
Ret
VSound_Get0:
Xor AL, AL
Pop ECX
Ret
VSound_GetDebugValue:
Pop EAX
Push ECX
Mov ECX, VSound_StatePos
Mov AL, [Byte Ptr VSound_DebugValue+ECX]
Inc ECX
And ECX, 3
Mov VSound_StatePos, ECX
Pop ECX
Ret
BeginProc VSound_Client_Hook
;---------------------------------------------------------------------
; Resolve Contention
;---------------------------------------------------------------------
Push EAX
Mov EAX, VSound_Client
Cmp VSound_ServerValid, 0
JE NoValidServer
Cmp EAX, EBX ; Is the request from the
JE Process_IO ; current owner?
Test EAX, EAX ; Was there a previous owner?
JZ New_Owner
NoValidServer:
Pop EAX
Dispatch_Byte_IO Fall_Through, <SHORT Blocked_IO>
Mov AL, 80h
Blocked_IO:
Ret
New_Owner:
Mov VSound_Client, EBX
Mov VSound_ClientCallback, 0
Process_IO:
Pop EAX
Dispatch_Byte_IO Fall_Through, <SHORT VSound_Out>
Push EAX
Mov EAX, VSound_State
Cmp EAX, VSOUND_CLIENTSTATES
JAE VSound_Unknown
Jmp [VSound_InTable+EAX*4]
VSound_Unknown:
Pop EAX
Xor AL, AL
Ret
VSound_Out:
Push EAX
Mov Byte Ptr VSound_State, AL
And EAX, 0FFh
Cmp EAX, VSOUND_CLIENTSTATES
JAE VSound_Out_Nothing
Jmp [VSound_OutTable+EAX*4]
VSound_Out_GetTSC:
DB 0Fh
DB 31h ; RdTSC
Mov VSound_TimeStamp1, EAX
Mov VSound_TimeStamp2, EDX
Jmp VSound_Out_ResetStatePos
VSound_Out_GetBufferUsed:
Mov EAX, VSound_TailPointer
Sub EAX, VSound_HeadPointer
And EAX, VSOUND_BUFFERSIZE-1
Mov VSound_BufferUsed, EAX
VSound_Out_ResetStatePos:
Mov VSound_StatePos, 0
VSound_Out_Nothing:
Pop EAX
Ret
VSound_Out_ResetClient:
Xor EAX, EAX
Mov VSound_Client, EAX
Mov VSound_ClientCallback, EAX
Pop EAX
Ret
VSound_Out_SetCallbackAddress:
Mov AX, [EBP+CLIENT_REG_STRUC.CLIENT_CS]
ShL EAX, 16
Mov AX, [EBP+CLIENT_REG_STRUC.CLIENT_BX]
Mov VSound_ClientCallback, EAX
Pop EAX
Ret
EndProc VSound_Client_Hook
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;--------------------------------------------------------------------
BeginProc VSound_Server_Hook
Push EAX
Mov EAX, VSound_Server
Cmp EAX, EBX ; Is the request from the
JE Process_Server_IO ; current owner?
Test EAX, EAX ; Was there a previous owner?
JZ New_Server
Pop EAX
Dispatch_Byte_IO Fall_Through, <SHORT Server_Blocked_IO>
Mov AL, 80h
Server_Blocked_IO:
Ret
New_Server:
Mov VSound_Server, EBX
Process_Server_IO:
Pop EAX
Dispatch_Byte_IO Fall_Through, <SHORT VSound_Server_Out>
Cmp VSound_ServerValid, 1
JE VSound_Server_Validated
Mov ECX, VSound_ServerInPos
Mov AL, [VSound_ServerID+ECX]
Inc ECX
And ECX, 7
Mov VSound_ServerInPos, ECX
Ret
VSound_Server_Validated:
Mov ECX, VSound_Client
Add ECX, 0FFFFFFFFh
SBB AL, AL ; Returns 0 if not connected, 0FFh if connected
Ret
VSound_Server_Out:
Test AL, AL ; Reset?
JZ VSound_Server_Reset
Mov ECX, VSound_ServerOutPos
Cmp VSound_ServerValid, 1
JE VSound_ReceiveServerString
Cmp [VSound_ServerID+ECX], AL
JE VSound_ValidByte
Mov VSound_ServerOutPos, 0
Ret
VSound_ValidByte:
Inc ECX
And ECX, 7
Mov VSound_ServerOutPos, ECX
JNZ VSound_ServerNotValidated
Mov VSound_ServerValid, 1
VSound_ServerNotValidated:
Ret
VSound_ReceiveServerString:
Mov [VSound_ServerString+ECX], AL
Inc ECX
And ECX, 63
Mov VSound_ServerOutPos, ECX
Ret
VSound_Server_Reset:
Xor ECX, ECX
Mov VSound_Server, ECX
Mov VSound_ServerValid, ECX
Mov VSound_ServerInPos, ECX
Mov VSound_ServerOutPos, ECX
Ret
EndProc VSound_Server_Hook
;---------------------------------------------------------------------
BeginProc VSound_Data_Hook
Cmp EBX, VSound_Server
JE VSound_Data_Server
Cmp EBX, VSound_Client
JE VSound_Data_Client
Ret
VSound_Data_Client:
Cmp CX, String_IO or Rep_IO or Byte_Output
JNE Data_Client_Simulate
PushAD
Push ES
PushF
ClI
Push DS
Pop ES
ShR ECX, 16 ; ECX = segment.
Mov EAX, [EBP+CLIENT_REG_STRUC.CLIENT_ECX]
ShL ECX, 4
Mov ESI, [EBP+CLIENT_REG_STRUC.CLIENT_ESI]
And ESI, 0FFFFh
Mov EDI, VSound_TailPointer
Add ESI, ECX ; ESI = data source.
And EAX, 0FFFFh ; EAX = byte count
Test EAX, 3 ; Must be multiple of 4 bytes
JNZ VSound_DataClientExit
LEA EDX, [EDI+EAX]
Add EDI, Offset VSound_Data
Cmp EDX, VSOUND_BUFFERSIZE
JB VSound_DataClient1
Mov ECX, VSOUND_BUFFERSIZE
LEA EAX, [EDX-VSOUND_BUFFERSIZE]
Sub ECX, VSound_TailPointer
ShR ECX, 2
Rep MovsD
Mov EDI, Offset VSound_Data
VSound_DataClient1:
ShR EAX, 2
And EDX, VSOUND_BUFFERSIZE-1
Mov ECX, EAX
Mov VSound_TailPointer, EDX
Rep MovsD
VSound_DataClientExit:
PopF
Pop ES
PopAD
Data_Client_Simulate:
Ret
VSound_Data_Server:
;
; The server will only receive data if:
; 1) A Rep InsB instruction is used. No other instruction will work
; 2) The ECX count is a multiple of 4
; 3) The ECX count must be less than BUFFERSIZE
Cmp CX, String_IO or Rep_IO or Addr_32_IO or Byte_Input
JNE Data_Server_Simulate
PushAD
Push ES
PushF
ClI
ShR ECX, 16
Mov ES, CX
Mov EAX, [EBP+CLIENT_REG_STRUC.CLIENT_ECX]
Mov EDI, [EBP+CLIENT_REG_STRUC.CLIENT_EDI]
Test EAX, 3
JNZ VSound_DataServerExit
Cmp EAX, VSOUND_BUFFERSIZE
JAE VSound_DataServerExit
; Want minimum of bytes available and bytes requested
Mov ESI, VSound_HeadPointer
Mov EBX, VSound_TailPointer
Sub EBX, ESI
And EBX, VSOUND_BUFFERSIZE-1 ; EBX = bytes available
; EAX = bytes requested
Cmp EBX, EAX
JB VSound_DataServer1
Mov EBX, EAX
VSound_DataServer1: ; EBX = bytes to transfer
Sub EAX, EBX ; EAX = bytes to zero
LEA EDX, [ESI+EBX]
ShR EBX, 2 ; EBX = dwords to transfer
Add ESI, Offset VSound_Data
Cmp EDX, VSOUND_BUFFERSIZE ; Does it span the buffer boundary?
JB VSound_DataServer2
LEA EBX, [EDX-VSOUND_BUFFERSIZE]
Mov ECX, VSOUND_BUFFERSIZE
ShR EBX, 2
Sub ECX, VSound_HeadPointer
ShR ECX, 2
Rep MovsD
Mov ESI, Offset VSound_Data
VSound_DataServer2:
ShR EAX, 2
Mov ECX, EBX
Rep MovsD
Mov ECX, EAX
And EDX, VSOUND_BUFFERSIZE-1
Xor EAX, EAX
Mov VSound_HeadPointer, EDX
Rep StosD
; ECX = 0
Mov EBX, VSound_Client
Cmp VSound_ClientCallback, ECX
JE VSound_DataServerExit
Test EBX, EBX
JZ VSound_DataServerExit
Mov EBP, [EBX+CB_S.CB_Client_Pointer]
VMMCall Set_Execution_Focus
JC VSound_DataServerExit
Push_Client_State
VMMCall Begin_Nest_V86_Exec
MovZX EDX, Word Ptr [VSound_ClientCallback]
MovZX ECX, Word Ptr [VSound_ClientCallback+2]
VMMCall Simulate_Far_Call
VMMCall Resume_Exec
VMMCall End_Nest_Exec
Pop_Client_State
VSound_DataServerExit:
PopF
Pop ES
PopAD
Data_Server_Simulate:
Ret
EndProc VSound_Data_Hook
;---------------------------------------------------------------------
VxD_CODE_ENDS
END