	page    58,132
	title   viwd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;   NAME:  VIWD.ASM $Revision: 1.18 $
;;  COPYRIGHT:
;;  "Copyright (c) 1994,1995 by e-Tek Labs"
;;
;;       "This software is furnished under a license and may be used,
;;       copied, or disclosed only in accordance with the terms of such
;;       license and with the inclusion of the above copyright notice.
;;       This software or any other copies thereof may not be provided or
;;       otherwise made available to any other person. No title to and
;;       ownership of the software is hereby transfered."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $Log: viwd.asm $
; Revision 1.18  1996/02/02 13:52:25  unknown
; Corrected win 3.1 bug if DMA channels set to same value
; Revision 1.17  1995/12/11 08:25:13  teckert
; Moved IRQ Descriptor Block from init to locked data segment.
; Revision 1.16  1995/11/28 10:54:06  teckert
; Changed allocation code to make callbacks to the ring 3 driver when a dos
; box allocates the hardware, also supports Sys VM access to the CODEC 
; anytime.
; Revision 1.15  1995/10/16 15:41:53  unknown
; Added copyright
; Revision 1.14  1995/10/16 14:41:01  unknown
; Added issue and revokation of PnP key
; Revision 1.13  1995/09/21 16:04:31  teckert
; Added Read_DMA_Count API function
; Revision 1.12  1995/09/12 19:08:40  teckert
; Changed sys_crit_init to read the sb and mpu401 irq's and bases
; Revision 1.11  1995/09/08 11:03:31  teckert
; Rolled in the windows 95 modifications
; Revision 1.10  1995/06/28 11:30:40  teckert
; Added close file to the real-mode init segment
; Revision 1.9  1995/05/12 10:09:38  teckert
; Added hex support in real mode init atoi function
; Revision 1.8  1995/05/07 18:48:37  teckert
; Reads DMA buffer sizes from system.ini
; Revision 1.7  1995/05/04 17:03:38  teckert
; Added real mode init segment
; Revision 1.6  1995/04/18 22:54:43  mleibow
; fixed wayward JMP if seperate DMA channels specified
; Revision 1.5  1995/04/18 15:32:31  teckert
; Added priority access for windows mixer
; Revision 1.4  1995/04/10 13:44:45  teckert
; IFDEF'd out the DMA virtualization section
; Revision 1.3  1995/04/06 18:42:38  teckert
; Added "Boss in a box" to driver
; Revision 1.2  1995/03/20 16:25:10  teckert
; Added file header
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	.386p

;
;** viwd.asm
;*
;*  DESCRIPTION:
;*  Virtual device for the InterWave
;*

;*****************************  INCLUDES  **********************************

.xlist
	include vmm.inc         ; this be required... unless your crazy.
	include debug.inc       ; optional; enabled if DEBUG defined
	include vdmad.inc
	include vpicd.inc
.list
	include viwd.inc

VxD_LOCKED_CODE_SEG
EXTRN   IW_IRQ_Hw_Int_Proc:NEAR
EXTRN   IW_IRQ_EOI_Proc:NEAR
EXTRN   IW_IRQ_Mask_Changed_Proc:NEAR
EXTRN   VIWD_VM_Not_Executeable:NEAR
VxD_LOCKED_CODE_ENDS    

VxD_CODE_SEG
EXTRN   IW_API_Get_Version:NEAR
EXTRN   IW_API_Acquire_InterWave:NEAR
EXTRN   IW_API_Release_InterWave:NEAR
EXTRN   IW_API_Register_SBOS_Support:NEAR
EXTRN   IW_API_SBOS_Functions:NEAR
EXTRN   IW_API_Register_Driver_Callback:NEAR
EXTRN   IW_API_Get_Buffer:NEAR
EXTRN   IW_API_Get_Resource_Config:NEAR
EXTRN   IW_API_Read_Port_Byte:NEAR
EXTRN   IW_API_Write_Port_Byte:NEAR
EXTRN   IW_API_Read_DMA_Count:NEAR
VxD_CODE_ENDS

;********************  VIRTUAL DEVICE DECLARATION  *************************

Declare_Virtual_Device VIWD, VIWD_VERMAJ, VIWD_VERMIN, \
                       VIWD_Control,VIWD_DEV_ID,,VIWD_API_Proc, \
                       VIWD_API_Proc


VxD_LOCKED_DATA_SEG
	align   4

DMA_Buffer_Phys          dd      0 ; first page of DMA buffer
DMA_Buffer_Linr          dd      0 ; linear address
	public  INTERWAV_CB_Offset
INTERWAV_CB_Offset       dd      0

	public _gIWI
_gIWI    INTERWAVEINFO <>        ; aldadatadaeriz

IW_IRQ_Descriptor VPICD_IRQ_Descriptor <,,        \
			    offset32 IW_IRQ_Hw_Int_Proc,,     \
			    offset32 IW_IRQ_EOI_Proc,         \
			    offset32 IW_IRQ_Mask_Changed_Proc,,>

VxD_LOCKED_DATA_ENDS


;***************  INITIALIZATION DATA SEG: PROTECT MODE  *******************


VxD_IDATA_SEG
COPYRIGHT_NOTICE         db      'Copyright 1992, 1995 Advanced Gravis, Inc. All rights reserved.',0

SYS_INI_SECTION         db      'INTERWAV.DRV',0
SYS_INI_PLAY_ENTRY      db      'PlayBufSize',0
SYS_INI_REC_ENTRY       db      'RecordBufSize',0

nDMABufferPages dw      0   
iwl_pnp_read    dw      0

VxD_IDATA_ENDS


;************************  NORMAL VXD DATA SEG  ****************************

VxD_DATA_SEG

;;  API jump table

EXTRN IW_AL_Port_Table:WORD
EXTRN IW_2XR_Port_Table:WORD
EXTRN IW_3XR_Port_Table:WORD
EXTRN IW_3XRPort_Port_Table:WORD
EXTRN IW_CODEC_Port_Table:WORD
EXTRN IW_MPU401_Port_Table:WORD

VxD_DATA_ENDS

;************************  LOCKED VXD DATA SEG  ****************************

VxD_LOCKED_DATA_SEG

;------------------------------------------------------------------------------
;                 A P I   D I S P A T C H   T A B L E
;------------------------------------------------------------------------------

IW_API_TABLE  LABEL DWORD
	      .errnz InterWave_API_Get_Version - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Get_Version
	      .errnz InterWave_API_Get_Buffer - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Get_Buffer
	      .errnz InterWave_API_Acquire_InterWave - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Acquire_InterWave
	      .errnz InterWave_API_Release_InterWave - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Release_InterWave
	      .errnz InterWave_API_Register_SBOS_Support - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Register_SBOS_Support
	      .errnz InterWave_API_SBOS_Functions - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_SBOS_Functions
	      .errnz InterWave_API_Register_Driver_Callback - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Register_Driver_Callback
	      .errnz InterWave_API_Get_Resource_Config - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Get_Resource_Config
	      .errnz InterWave_API_Read_Port_Byte - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Read_Port_Byte
	      .errnz InterWave_API_Write_Port_Byte - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Write_Port_Byte
	      .errnz InterWave_API_Read_DMA_Count - ($-IW_API_TABLE)/4
	dd  offset32 IW_API_Read_DMA_Count

IW_API_MAX    equ ($-IW_API_TABLE)/4


	public _gIW_ResTbl
_gIW_ResTbl LABEL WORD
	   IWRESOURCEINFO <IWRIS_IRQ,,,,,?>     ; IWAR_IRQ1
	   IWRESOURCEINFO <IWRIS_IRQ,,,,,?>     ; IWAR_IRQ2
	   IWRESOURCEINFO <IWRIS_DMA,,,,,?>             ; IWAR_DMA1
	   IWRESOURCEINFO <IWRIS_DMA,,,,,?>             ; IWAR_DMA2
	   IWRESOURCEINFO <(IWRIS_PORTS OR IWRIS_3XR),,,,offset32 IW_3XR_Port_Table,?>  ; IWAR_SOMEVOICES
	   IWRESOURCEINFO <IWRIS_OTHER,,,,,?>           ; IWAR_ALLVOICES
	   IWRESOURCEINFO <IWRIS_OTHER,,,,,?>           ; IWAR_SOMEMEMORY
	   IWRESOURCEINFO <IWRIS_OTHER,,,,,?>           ; IWAR_ALLMEMORY
	   IWRESOURCEINFO <(IWRIS_PORTS OR IWRIS_CODAR),,,,offset32 IW_CODEC_Port_Table,?>      ; IWAR_CODECPLAY
	   IWRESOURCEINFO <IWRIS_OTHER,,,,,?>           ; IWAR_CODECREC
	   IWRESOURCEINFO <(IWRIS_OTHER OR IWRIS_CODAR),,,,,?> ; IWAR_CODECMIX
	   IWRESOURCEINFO <(IWRIS_PORTS OR IWRIS_3XR),,,,offset32 IW_3XRPort_Port_Table,?>      ; IWAR_PORTIN
	   IWRESOURCEINFO <IWRIS_OTHER,,,,,?>           ; IWAR_PORTOUT
	   IWRESOURCEINFO <03000h OR IWRIS_PORTS,,,,offset32 IW_AL_Port_Table,?>  ; IWAR_VADLIB
	   IWRESOURCEINFO <(IWRIS_PORTS OR IWRIS_2XR OR IWRIS_SBOS),,,,offset32 IW_2XR_Port_Table,?>  ; IWAR_VSNDBLST
	   IWRESOURCEINFO <(04000h OR IWRIS_PORTS OR IWRIS_MPUR),,,,offset32 IW_MPU401_Port_Table,?>      ; IWAR_VMPU401

VxD_LOCKED_DATA_ENDS

VxD_REAL_INIT_SEG

;** VIWD_Real_Mode_Init
;*
;*

BeginProc VIWD_Real_Mode_Init

	push    ds
	push    cs
	pop     ds

	jmp     Begin_Init

;        align 4 
abStack         dw      1024 dup ('BW')
wSS             dw      0
wSP             dw      0

interwave       db      'INTERWAVE='
interwave_size  equ     ($ - interwave)
setup           db      '[setup 0]'
setup_size      equ     ($ - setup)
pnprdp          db      'pnprdp='
pnprdp_size     equ     ($ - pnprdp)
buff_size       equ     132
csn             db      'csn='
csn_size        equ     ($ - csn)
buff            db      buff_size dup (?)
file_handle     dw      0
pnprdp_num      dw      0
csn_num         dw      0
done            dw      0
FOUND_PNPRDP    EQU     1
FOUND_CSN       EQU     2
FOUND_ALL       EQU     (FOUND_PNPRDP OR FOUND_CSN)
msg_interwave_not_found db      "INTERWAVE environment not found.",10,13,"$"
msg_cant_open           db      "Can't open configuration file.",10,13,"$"
msg_setup_not_found     db      "Can't find [setup 0] section in configuration file.",10,13,"$"
msg_pnp_info_not_found  db      "Can't find pnprdp= or csn= in configuration file.",10,13,"$"
	
Begin_Init:  
; Switch to our stack
	mov     wSS, ss
	mov     wSP, sp

	;
	; Set up the stack...
	;

	push    ds
	pop     ss
	lea     di, abStack
	add     di, 2048
	mov     sp, di

	push    bp
	mov     bp, sp

	sub     sp, 4
	
	push    ds
	pop     es
	
	mov     done, 0
	mov     ah, 51h
	int     21h
	mov     es, bx
	mov     es, es:[2ch]
	xor     di, di
	cld
try_again:
	mov     cx, interwave_size
	cmp     byte ptr es:[di], 0
	jne     short compare
	jmp     interwave_not_found
compare:
	push    di
	lea     si, interwave
	repe    cmpsb
	je      short found_interwave_environ
	pop     di
	inc     di
	mov     cx, 0ffffh
	mov     ax, 0
	repne   scasb
	jmp     try_again
	; open file with filename found in environment (es:di)
found_interwave_environ:

	pop     ax              ; restore stack
	mov     ax, 03D00h
	push    ds
	mov     bx, es
	mov     ds, bx
	mov     dx, di
	int     21h             ; open file
	pop     ds
	jc      cant_open
	mov     file_handle, ax
	; search for [setup 0] section
	push    ds
	pop     es

try_again_2:
	lea     si, buff
	mov     ax, file_handle
	call    readline
	jc      setup_not_found
	lea     si, buff
	lea     di, setup
	mov     cx, setup_size
	repe    cmpsb
	jne     try_again_2
; found [setup] section - now search for pnprdp and csn
try_again_3:
	lea     si, buff
	mov     ax, file_handle
	call    readline
	jc      pnp_info_not_found
	lea     si, buff
	lea     di, pnprdp
	mov     cx, pnprdp_size
	repe    cmpsb
	jne     short try_csn
	; found pnprdp
	mov     ax, 16
	call    atoi
	mov     pnprdp_num, ax
	or      done, FOUND_PNPRDP
	cmp     done, FOUND_ALL
	je      short outtahere
	jmp     try_again_3
try_csn:
	lea     si, buff
	lea     di, csn
	mov     cx, csn_size
	repe    cmpsb
	jne     try_again_3
	; found csn
	mov     ax, 16
	call    atoi
	mov     csn_num, ax
	or      done, FOUND_CSN
	cmp     done, FOUND_ALL
	je      short outtahere
	jmp     try_again_3
outtahere:
	mov     dx, pnprdp_num
	shl     edx, 16
	mov     dx, csn_num
	; edx contains (rdp<<16) + csn
	mov     ax,Device_Load_Ok
	jmp     short exit

interwave_not_found:
	lea     dx, msg_interwave_not_found
	mov     ah, 09h
	int     21h 
	mov     ax, Abort_Device_Load
	jmp     short exit
cant_open:
	lea     dx, msg_cant_open
	mov     ah, 09h
	int     21h
	mov     ax, Abort_Device_Load
	jmp     short exit
setup_not_found:
	lea     dx, msg_setup_not_found
	mov     ah, 09h
	int     21h
	mov     ax, Abort_Device_Load
	jmp     short exit
pnp_info_not_found:
	lea     dx, msg_pnp_info_not_found
	mov     ah, 09h
	int     21h
	mov     ax, Abort_Device_Load
	jmp     short exit

exit:
	push	ax
	push	bx
	mov     bx, file_handle
	or	bx,bx
	jz	short file_closed
	mov	ax,03E00h
	int	21h			; close the file
	
file_closed:      
	pop	bx
	pop	ax

	mov     bx,0
	mov     si,0
	;
	; Restore the stack
	;       
	add     sp, 4
	pop     bp

	mov     sp, wSP
	mov     ss, wSS

	pop     ds

	ret

EndProc VIWD_Real_Mode_Init

BeginProc readline
	; si contains pointer to buffer
	; ax contains file handle
	mov     bx, ax
	mov     ax, 3f00h
	mov     cx, buff_size
	dec     cx
	mov     dx, si
	int     21h
	jc      short readline_done
	or      ax, ax
	jz      short readline_eof
	mov     di, si
	mov     cx, ax
	mov     ax, 13  ; carraige return
	repne   scasb
	je      short found_cr
	mov     byte ptr [di], 0
	clc
	jmp     short readline_done
found_cr:
	dec     di
	mov     byte ptr [di], 0
	dec     cx
	; seek back cx bytes to beginning of next line
	mov     ax, 4201h       ; move from current position
	neg     cx
	mov     dx, cx
	mov     cx, 0ffffh      ; cx:dx = offset
	; bx should still contain file handle
	int     21h
readline_done:
	ret
readline_eof:
	stc
	jmp     readline_done
EndProc readline

BeginProc atoi
	mov     dx, ax
	xor     ax, ax
atoi_loop:
	mov     bl, [si]
	inc     si
	cmp     bl, '0'
	jl      short atoi_not_decimal
	cmp     bl, '9'
	jg      short atoi_not_decimal
	sub     bl, '0'
	jmp     short atoi_got_number

atoi_not_decimal:
	cmp     dl,10
	jle     short atoi_done

	cmp     bl, 'a'
	jl      short atoi_not_lc
	cmp     bl, 'f'
	jg      short atoi_done
	sub     bl, ('a'-10)
	jmp     short atoi_got_number

atoi_not_lc:
	cmp     bl, 'A'
	jl      short atoi_done
	cmp     bl, 'F'
	jg      short atoi_done
	sub     bl, ('A'-10)

atoi_got_number:
	mul     dl
	mov     bh, 0
	add     ax, bx
	jmp     atoi_loop
atoi_done:
	ret
EndProc atoi

VxD_REAL_INIT_ENDS


;***************  INITIALIZATION CODE SEG: PROTECT MODE  *******************

VxD_ICODE_SEG

;** VIWD_Sys_Crit_Init
;*
;*  DESCRIPTION:
;*      Phase 1.  When this function is called, interrupts are not yet
;*      enabled.  Therefore, this phase should accomplish the following
;*      tasks as quickly as possible:
;*
;*              o  Initialization of critical functions necessary
;*                 when interrupts are enabled.
;*
;*              o  Claiming a particular range of V86 pages if
;*                 necessary (such as the video memory for the VDD).
;*
;*              o  Initialization of data needed by the services
;*                 provided by this VxD (FAST stuff).
;*                 
;*              o  During this phase, the System VM Simulate_Int
;*                 and Exec_Int commands must NOT be used (can't).
;*
;*  ENTRY:
;*      EBX     :       VM Handle.
;*      EDX     :       Reference data from real-mode initialization segment
;*                      csn in loword, port in hiword
;*
;*  EXIT:
;*      Carry clear if successful.  Set if fail--this will keep this
;*      VxD from loading.
;*
;*  NOTES:
;*
;** cjp *

BeginProc VIWD_Sys_Crit_Init

loop_cnt	db 0
msb		db 0

;
;       Initialize the fields of the INTERWAVEINFO structure.
;       These values are read from the PNP registers on the board
;
	mov     ecx,edx                 ; store the csn and port in ecx
	ror     edx,16
	mov     [iwl_pnp_read],dx       ; store the read port
; FIRST SEND THE KEY

	push	edx
	push	ecx
	mov	bl,6Ah
	mov	dx,IWL_PNP_INDEX
	mov	al,0
	out	dx,al
	out	dx,al
	mov	dx,IWL_PNP_INDEX
	mov	al,bl
	out	dx,al
	mov	loop_cnt,1
	jmp	short key_loop_chk
key_loop:
   ;	
   ;		msb = ((code&0x01)^((code&0x02)>>1))<<7;
   ;	
	mov	al,bl
	mov	ah,0
	and	ax,2
	sar	ax,1
	mov	dl,bl
	and	dl,1
	xor	dl,al
	mov	cl,7
	shl	dl,cl
	mov	msb,dl
   ;	
   ;		code = (code>>1)|msb;
   ;	
	mov	al,bl
	mov	ah,0
	sar	ax,1
	or	al,msb
	mov	bl,al
   ;	
   ;		OS_OUTPORTB(pidxr,code);
   ;	
	mov	dx,IWL_PNP_INDEX
	mov	al,bl
	out	dx,al
	inc	loop_cnt
key_loop_chk:
	cmp	loop_cnt,32
	jb	short key_loop
	pop	ecx
	pop	edx
	
	outpb   IWL_PNP_INDEX,IW_PWAKEI
	outpb   IWL_PNP_WRITE,cl

; Select PNP device
	outpb   IWL_PNP_INDEX,IW_PLDNI
	outpb   IWL_PNP_WRITE,IWL_PNP_AUDIO

;       Interrupt 1
	outpb   IWL_PNP_INDEX,IW_PUI1SI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_bIRQ1],al
	cmp     al,0FFh
	je      BOARD_NOT_PRESENT
	
;       Interrupt 2
	outpb   IWL_PNP_INDEX,IW_PUI2SI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_bIRQ2],al
	cmp     al,0FFh
	je      BOARD_NOT_PRESENT

;       DMA 1
	outpb   IWL_PNP_INDEX,IW_PUD1SI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_bDMA1],al
	cmp     al,0FFh
	je      BOARD_NOT_PRESENT

;       DMA 2
	outpb   IWL_PNP_INDEX,IW_PUD2SI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_bDMA2],al
	cmp     al,0FFh
	je      BOARD_NOT_PRESENT

;       wSynthBase
	outpb   IWL_PNP_INDEX,IW_P2X0HI
	inpb    iwl_pnp_read
	rol     ax,8    
	outpb   IWL_PNP_INDEX,IW_P2X0LI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_wSynthBase2X],ax
	cmp     ax,0FFFFh
	je      BOARD_NOT_PRESENT

	outpb   IWL_PNP_INDEX,IW_P3X0HI
	inpb    iwl_pnp_read
	rol     ax,8    
	outpb   IWL_PNP_INDEX,IW_P3X0LI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_wSynthBase3X],ax
	cmp     ax,0FFFFh
	je      BOARD_NOT_PRESENT

;       wCodecBase
	outpb   IWL_PNP_INDEX,IW_PHCAI
	inpb    iwl_pnp_read
	rol     ax,8    
	outpb   IWL_PNP_INDEX,IW_PLCAI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_wCodecBase],ax
	cmp     ax,0FFFFh
	je      BOARD_NOT_PRESENT
	
	; activate the audio device
	outpb   IWL_PNP_INDEX,IW_PUACTI
	outpb   IWL_PNP_WRITE,1    
	
;       wMPU401Base
	outpb   IWL_PNP_INDEX,IW_PLDNI
	outpb   IWL_PNP_WRITE,IWL_PNP_MPU401

	outpb   IWL_PNP_INDEX,IW_P401HI
	inpb    iwl_pnp_read
	rol     ax,8    
	outpb   IWL_PNP_INDEX,IW_P401LI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_wMPUBase],ax
	cmp     ax,0FFFFh
	je      BOARD_NOT_PRESENT 
	
	outpb	IWL_PNP_INDEX,IW_PMISI
	inpb	iwl_pnp_read
	mov	[_gIWI.iwi_bMPUIRQ],al

	; activate the MPU401 device
	outpb   IWL_PNP_INDEX,IW_PUACTI
	outpb   IWL_PNP_WRITE,1    
	
;	Adlib Base port and IRQ	
	outpb   IWL_PNP_INDEX,IW_PLDNI
	outpb   IWL_PNP_WRITE,IWL_PNP_ADLIB
	outpb   IWL_PNP_INDEX,IW_P388HI
	inpb    iwl_pnp_read
	rol     ax,8    
	outpb   IWL_PNP_INDEX,IW_P388LI
	inpb    iwl_pnp_read
	mov     [_gIWI.iwi_wAdlibBase],ax
	cmp     ax,0FFFFh
	je      BOARD_NOT_PRESENT
	
	outpb	IWL_PNP_INDEX,IW_PSBISI
	inpb	iwl_pnp_read
	mov	[_gIWI.iwi_bSBIRQ],al
	
	; activate the Adlib device
	outpb   IWL_PNP_INDEX,IW_PUACTI
	outpb   IWL_PNP_WRITE,1    
	
	; put the pnp state machine to sleep
	outpb   IWL_PNP_INDEX,IW_PCCCI
	outpb   IWL_PNP_WRITE,2
	
;       dwDMABufferSize
;
; Allocate DMA buffer
;
	mov     eax,8
	mov     esi,offset32 SYS_INI_SECTION
	mov     edi,offset32 SYS_INI_PLAY_ENTRY
	VMMCall Get_Profile_Decimal_Int
	add     eax,3
	and     eax,0FFCh
	ror     eax,2
	mov     [nDMABufferPages],ax
	
	mov     eax,8
	mov     esi,offset32 SYS_INI_SECTION
	mov     edi,offset32 SYS_INI_REC_ENTRY
	VMMCall Get_Profile_Decimal_Int
	add     eax,3
	and     eax,0FFCh
	ror     eax,2
	
;        mov     bl,[_gIWI.iwi_bDMA1]
;        cmp     bl,[_gIWI.iwi_bDMA2]
;        je      short OneDmaChannel
	add     ax,[nDMABufferPages]
;        jmp     short NumPagesKnown
;OneDmaChannel:                      
;        cmp     ax,[nDMABufferPages]
;        jge     short NumPagesKnown
;        mov     ax,[nDMABufferPages]
;NumPagesKnown:

	and     eax,03FFh
  
	mov     ebx,eax
	rol     eax, 12
	mov     [_gIWI.iwi_dwDMABufferSize],eax  
	mov     edi, OFFSET32 _gIWI.iwi_dwDMAPhysical
	mov     ecx, ebx
	sub     ecx, 1  
	VMMCall _PageAllocate <ebx,PG_SYS,0,ecx,MINPHYS,MAXPHYS,edi,PageUseAlign+PageContig+PageFixed>
	test    eax, eax
	jnz     SHORT GOT_DMA_BUFFER
	Debug_Out "INTERWAV ERROR:  Could not alloc DMA buffer"
	mov     [_gIWI.iwi_dwDMABufferSize],eax
	clc
	ret
;       jmp     SHORT NO_BUFFER

GOT_DMA_BUFFER:
	mov     [_gIWI.iwi_dwDMALinear], edx
NO_BUFFER:

; Get the IRQ and DMA numbers out of the info structure
	mov     edi,offset32 _gIW_ResTbl
; IRQ 1                                     
	cmp     [_gIWI.iwi_bIRQ1],0
	jnz     short IRQ_1_Present
	or      WORD PTR[edi.iwri_wStatus],IWRIS_OTHER
	jmp     short Check_IRQ_2
IRQ_1_Present:  
	movzx   eax,BYTE PTR[_gIWI.iwi_bIRQ1]
	mov     [edi.iwri_dwResourceID],eax
	add     edi,(size IWRESOURCEINFO)
; if IRQ 2 is different, otherwise make sure IRQ 1 is set for IRQ 2 and change
; IRQ 2 to OTHER
Check_IRQ_2:
	cmp     [_gIWI.iwi_bIRQ2],0
	je      short ONLY_ONE_IRQ
	movzx   eax,BYTE PTR[_gIWI.iwi_bIRQ2]
	cmp     al,[_gIWI.iwi_bIRQ1]
	je      short ONLY_ONE_IRQ
	mov     [edi.iwri_dwResourceID],eax
	jmp     short CHECK_DMA_CHANNELS
ONLY_ONE_IRQ:
	or      WORD PTR[edi.iwri_wStatus],IWRIS_OTHER

CHECK_DMA_CHANNELS:
	add     edi,(size IWRESOURCEINFO)
; DMA 1                     
	movzx   eax,BYTE PTR[_gIWI.iwi_bDMA1]
	mov     [edi.iwri_dwResourceID],eax
	add     edi,(size IWRESOURCEINFO)
; if DMA 2 is different, otherwise make sure DMA 1 is set for DMA 2 and change
; DMA 2 to OTHER
	cmp     [_gIWI.iwi_bDMA2],0
	je      short ONLY_ONE_DMA
	movzx   eax,BYTE PTR[_gIWI.iwi_bDMA2]
	mov     [edi.iwri_dwResourceID],eax
	jmp     short CRIT_INIT_DONE
ONLY_ONE_DMA:
	or      WORD PTR[edi.iwri_wStatus],IWRIS_OTHER
	
CRIT_INIT_DONE:
	clc                             ; no error
	ret

BOARD_NOT_PRESENT:
	; put the pnp state machine to sleep
	outpb   IWL_PNP_INDEX,IW_PWAKEI
	outpb   IWL_PNP_WRITE,0

	stc
	ret
	
EndProc VIWD_Sys_Crit_Init



;** VIWD_Device_Init
;*
;*  DESCRIPTION:
;*      Phase 2.  This is where the bulk of your initialization should
;*      be done.  Interrupts are enabled now and the Simulate_Int and 
;*      Exec_Int services are allowed.  During this phase, you can:
;*
;*              o  Allocate your Control Block area and misc. memory.
;*
;*              o  Hook interrupts and I/O ports.
;*
;*              o  Specify instance data.
;*
;*      The System VM's Control Block should be set up with the initial
;*      state of the VxD.  Since the System VM has already been created
;*      calls such as Simulate_Int or Exec_Int are allowed.
;*
;*  ENTRY:
;*      EBX     :       VM Handle.
;*
;*  EXIT:
;*      Carry clear if successful.  Set if fail--this will keep this
;*      VxD from loading.
;*
;*  NOTES:
;*

BeginProc VIWD_Device_Init
 
	VMMcall _Allocate_Device_CB_Area, <<SIZE INTERWAV_CB_DATA>, 0>
	test    eax, eax
	jnz     short INTERWAV_CB_OK

	Debug_Out "INTERWAV_Device_Init: _Allocate_Device_CB_Area failed!"
	VMMcall Fatal_Memory_Error

INTERWAV_CB_OK:
	mov     [INTERWAV_CB_Offset], eax        ; gotta keep this around


	mov	eax,0
	call	_VIWD_Init_Logical_Device
        or      [_gIWI.iwi_bDeviceInit],IWINFO_DEV0_INIT

	mov	eax,3
	call	_VIWD_Init_Logical_Device
        or      [_gIWI.iwi_bDeviceInit],IWINFO_DEV3_INIT

	mov	eax,4
	call	_VIWD_Init_Logical_Device
        or      [_gIWI.iwi_bDeviceInit],IWINFO_DEV4_INIT

	ret
EndProc VIWD_Device_Init



VxD_ICODE_ENDS



;**************************  LOCKED CODE SEG  ******************************


VxD_LOCKED_CODE_SEG


;** VIWD_Control
;*
;*  DESCRIPTION:
;*
;*  ENTRY:
;*
;*  EXIT:
;*
;*  NOTES:
;*
;** cjp *

BeginProc VIWD_Control

        Control_Dispatch Sys_Critical_Init,     VIWD_Sys_Crit_Init
        Control_Dispatch Device_Init,           VIWD_Device_Init
        Control_Dispatch System_Exit,           VIWD_System_Exit

IFDEF _WIN95
	    Control_Dispatch SYS_DYNAMIC_DEVICE_INIT, VIWD_Dyn_Device_Init
        Control_Dispatch PNP_NEW_DEVNODE, VIWD_NewDevNode, sCall, <ebx, edx>
ENDIF

        Control_Dispatch VM_Not_Executeable,    VIWD_VM_Not_Executeable

	clc
	ret

EndProc VIWD_Control


BeginProc HandleDMAAction

	VMMCall Test_Sys_VM_Handle              ; no need to check sys VM
	je      SHORT IW_HDA_Exit

	VxDCall VDMAD_Get_Virt_State

	and     dl, NOT (DMA_mode_mask)         ; assure DMA_demand_mode

	test    [_gIWI.iwi_wFlags], IWI_FLAG_SINGLEMODEDMA
	jz      SHORT IW_HDA_NotSingleMode
	or      dl, DMA_single_mode

IW_HDA_NotSingleMode:
	xor     dh, dh
	VxDCall VDMAD_Set_Virt_State

IW_HDA_Exit:
	VxDCall VDMAD_Default_Handler
	ret

EndProc HandleDMAAction

VxD_LOCKED_CODE_ENDS
 
;*************************  PROTECT MODE CODE SEG  *************************

VxD_CODE_SEG


;** VIWD_Init_Logical_Device
;*
;*  DESCRIPTION:
;*	This function is called either from Device_Init for static loading or from
;*	CONFIG_START in the configuration manager callback routine.
;*
;*  ENTRY:
;*	EAX	:	0, 3, or 4 the logical device
;*      EBX     :       VM Handle.
;*
;*  EXIT:
;*      Carry clear if successful.  Set if fail--this will keep this
;*      VxD from loading.
;*
;*  NOTES:
;*
BeginProc _VIWD_Init_Logical_Device

	push	edx
	push	edi
        push	esi
	push	ecx

        rol	eax,12
        push	eax

; Install the interrupt handlers I/O handlers and DMA handlers as needed
	mov     edi,offset32 _gIW_ResTbl
	mov     ecx,IWAR_NUMRESOURCES

IWDI_RESOURCE_LOOP:
	pop	edx
	movzx   eax,WORD PTR[edi.iwri_wStatus]
        and     eax,0F000h
	cmp	eax,edx
	push	edx
	jne	short RESOURCE_INSTALLED
			
	movzx   eax,WORD PTR[edi.iwri_wStatus]
	and     ax,IWRIS_TYPE

	cmp     ax,IWRIS_IRQ
	je      short INSTALL_IRQ_RESOURCE
	
	cmp     ax,IWRIS_DMA
	je      INSTALL_DMA_RESOURCE
	
	cmp     ax,IWRIS_PORTS
	je      short INSTALL_PORT_RESOURCE
	
RESOURCE_INSTALLED:
	add     edi,(size IWRESOURCEINFO)              
	loop    IWDI_RESOURCE_LOOP
	jmp     ALL_RESOURCES_INSTALLED

INSTALL_IRQ_RESOURCE:
	mov     ax, WORD PTR [edi.iwri_dwResourceID]
	mov     [IW_IRQ_Descriptor.VID_IRQ_Number],ax
	push    edi
	mov     edi,OFFSET32 IW_IRQ_Descriptor
	VxDcall VPICD_Virtualize_IRQ
	pop     edi
	jc      DISABLE_RESOURCE
	mov     [edi.iwri_dwResourceHandle],eax
	
	jmp     RESOURCE_INSTALLED
	
INSTALL_PORT_RESOURCE:
	push    ecx
	test    WORD PTR [edi.iwri_wStatus],IWRIS_2XR
	jz      short TEST_3XR       
	mov     dx,[_gIWI.iwi_wSynthBase2X]
	jmp     short ADD_OFFSET_TO_PORTS
TEST_3XR:       
	test    WORD PTR [edi.iwri_wStatus],IWRIS_3XR
	jz      short TEST_CODAR
	mov     dx,[_gIWI.iwi_wSynthBase3X]
	jmp     short ADD_OFFSET_TO_PORTS
TEST_CODAR:     
	test    WORD PTR [edi.iwri_wStatus],IWRIS_CODAR
	jz      short TEST_MPUR
	mov     dx,[_gIWI.iwi_wCodecBase]
	jmp     short ADD_OFFSET_TO_PORTS
TEST_MPUR:      
	test    WORD PTR [edi.iwri_wStatus],IWRIS_MPUR
	jz      short GET_PORT_RANGE
	mov     dx,[_gIWI.iwi_wMPUBase]
	
ADD_OFFSET_TO_PORTS:             
	mov     esi, [edi.iwri_dwResourceHandle]
	movzx   ecx, WORD PTR[esi]          ; get the count
	add     esi, (size VxD_IOT_Hdr)
IW_Offset_Loop:
	add     [esi.VxD_IO_Port], dx       ; add port base to offset
	add     esi, (size VxD_IO_Struc)
	loop    IW_Offset_Loop
	
GET_PORT_RANGE:
	xor     edx,edx
	mov     esi, [edi.iwri_dwResourceHandle]
	movzx   ecx, WORD PTR[esi]      ; get the count
	add     esi, (size VxD_IOT_Hdr)
	mov     dx,[esi.VxD_IO_Port]    ; lowport
	shl     edx,16                  ; store in the hiword
	dec     ecx
	jecxz   SHORT SINGLE_PORT
	
IWDI_FIND_LAST_PORT:
	add     esi, (size VxD_IO_Struc)
	loop    IWDI_FIND_LAST_PORT

SINGLE_PORT:
	mov     dx,[esi.VxD_IO_Port]    ; hiport in loword
	ror     edx,16                  ; exchange hiword and loword
	mov     [edi.iwri_dwResourceID],edx     ; store port range
	
INSTALL_PORT_HANDLERS:
	push    edi
	push    edi
	pop     esi
	mov     edi,[esi.iwri_dwResourceHandle]
	VMMcall Install_Mult_IO_Handlers        
	pop     edi
	pop     ecx
	jc      short DISABLE_RESOURCE        
	jmp     RESOURCE_INSTALLED
	
INSTALL_DMA_RESOURCE:
; If DMA channel one is set to 1 and this is the channel one resource and the DMA
; channel has not yet been virtualized then virtualize the DMA channel
IFDEF VIRTUALIZE_DMA_CHAN_1
	cmp     [_gIWI.iwi_bDMA1],1
	jne     RESOURCE_INSTALLED
	cmp     [edi.iwri_dwResourceID],1
	jne     RESOURCE_INSTALLED
	test    [_gIWI.iwi_wFlags],IWI_FLAG_DMA_VIRTUALIZED
	jnz     RESOURCE_INSTALLED
	mov     eax, [edi.iwri_dwResourceID]
	mov     esi, OFFSET32 HandleDMAAction
	VxDcall VDMAD_Virtualize_Channel
	jc      short DISABLE_RESOURCE
	or      [_gIWI.iwi_wFlags],IWI_FLAG_DMA_VIRTUALIZED
	mov     [edi.iwri_dwResourceHandle],eax
ENDIF
	jmp     RESOURCE_INSTALLED

DISABLE_RESOURCE:       
	or      WORD PTR [edi.iwri_wStatus],IWRIS_DISABLED
	jmp     RESOURCE_INSTALLED

ALL_RESOURCES_INSTALLED:
	pop	eax

	pop	ecx
	pop	esi
	pop	edi
	pop	edx

	clc             ; no error
	ret
EndProc _VIWD_Init_Logical_Device


IFDEF _WIN95

;** VIWD_Uninit_Logical_Device
;*
;*  DESCRIPTION:
;*	This function is called either from CONFIG_STOP to free the resources
;*
;*  ENTRY:
;*	EAX	:	0, 3, or 4 the logical device
;*      EBX     :       VM Handle.
;*
;*  EXIT:
;*      Carry clear if successful.  Set if fail--this will keep this
;*      VxD from loading.
;*
;*  NOTES:
;*
BeginProc _VIWD_Uninit_Logical_Device

	push	edx
	push	edi
        push	esi
	push	ecx

        rol	eax,12
        push	eax

; Free the interrupt handlers I/O handlers and DMA handlers as needed
	mov     edi,offset32 _gIW_ResTbl
	mov     ecx,IWAR_NUMRESOURCES

IWDU_RESOURCE_LOOP:
	pop	edx
	movzx   eax,WORD PTR[edi.iwri_wStatus]
        and     eax,0F000h
	cmp	eax,edx
	push	edx
	jne	short RESOURCE_UNINSTALLED
			
	movzx   eax,WORD PTR[edi.iwri_wStatus]
	and     ax,IWRIS_TYPE

	cmp     ax,IWRIS_IRQ
	je      short UNINSTALL_IRQ_RESOURCE
	
	cmp     ax,IWRIS_DMA
	je      UNINSTALL_DMA_RESOURCE
	
	cmp     ax,IWRIS_PORTS
	je      short UNINSTALL_PORT_RESOURCE
	
RESOURCE_UNINSTALLED:
	add     edi,(size IWRESOURCEINFO)              
	loop    IWDU_RESOURCE_LOOP
	jmp     ALL_RESOURCES_UNINSTALLED

UNINSTALL_IRQ_RESOURCE:
	mov     eax,[edi.iwri_dwResourceHandle]
	VxDcall VPICD_Force_Default_Behavior
	
	jmp     RESOURCE_UNINSTALLED
	
UNINSTALL_PORT_RESOURCE:
	push    ecx

	push    edi
	push	edi
	pop	esi
	mov     edi,[esi.iwri_dwResourceHandle]
	VMMcall Remove_Mult_IO_Handlers        
	pop     edi

	test    WORD PTR [edi.iwri_wStatus],IWRIS_2XR
	jz      short RETEST_3XR       
	mov     dx,[_gIWI.iwi_wSynthBase2X]
	jmp     short SUB_OFFSET_FROM_PORTS
RETEST_3XR:       
	test    WORD PTR [edi.iwri_wStatus],IWRIS_3XR
	jz      short RETEST_CODAR
	mov     dx,[_gIWI.iwi_wSynthBase3X]
	jmp     short SUB_OFFSET_FROM_PORTS
RETEST_CODAR:     
	test    WORD PTR [edi.iwri_wStatus],IWRIS_CODAR
	jz      short RETEST_MPUR
	mov     dx,[_gIWI.iwi_wCodecBase]
	jmp     short SUB_OFFSET_FROM_PORTS
RETEST_MPUR:      
	test    WORD PTR [edi.iwri_wStatus],IWRIS_MPUR
	jz      short PORT_RESOURCE_UNINIT_COMPLETE
	mov     dx,[_gIWI.iwi_wMPUBase]
	
SUB_OFFSET_FROM_PORTS:             
	mov     esi, [edi.iwri_dwResourceHandle]
	movzx   ecx, WORD PTR[esi]          ; get the count
	add     esi, (size VxD_IOT_Hdr)

IWU_Offset_Loop:
	sub     [esi.VxD_IO_Port], dx       ; subtract port base from offset
	add     esi, (size VxD_IO_Struc)
        loop    IWU_Offset_Loop
	
PORT_RESOURCE_UNINIT_COMPLETE:
	pop     ecx
	jmp     RESOURCE_UNINSTALLED
	
UNINSTALL_DMA_RESOURCE:
; If DMA channel one is set to 1 and this is the channel one resource and the DMA
; channel has not yet been virtualized then virtualize the DMA channel
IFDEF VIRTUALIZE_DMA_CHAN_1
	cmp     [_gIWI.iwi_bDMA1],1
	jne     RESOURCE_INSTALLED
	cmp     [edi.iwri_dwResourceID],1
	jne     RESOURCE_INSTALLED
	test    [_gIWI.iwi_wFlags],IWI_FLAG_DMA_VIRTUALIZED
	jnz     RESOURCE_INSTALLED
	mov     eax, [edi.iwri_dwResourceID]
	mov     esi, OFFSET32 HandleDMAAction
	VxDcall VDMAD_Virtualize_Channel
	jc      short DISABLE_RESOURCE
	or      [_gIWI.iwi_wFlags],IWI_FLAG_DMA_VIRTUALIZED
	mov     [edi.iwri_dwResourceHandle],eax
ENDIF
	jmp     RESOURCE_UNINSTALLED

ALL_RESOURCES_UNINSTALLED:
	pop	eax

	pop	ecx
	pop	esi
	pop	edi
	pop	edx

	clc             ; no error
	ret
EndProc _VIWD_Uninit_Logical_Device

ENDIF

;** VIWD_Dyn_Device_Init
;*
;*  DESCRIPTION:
;*      Phase 2.  This is where the bulk of your initialization should
;*      be done.  Interrupts are enabled now and the Simulate_Int and 
;*      Exec_Int services are allowed.  During this phase, you can:
;*
;*              o  Allocate your Control Block area and misc. memory.
;*
;*              o  Hook interrupts and I/O ports.
;*
;*              o  Specify instance data.
;*
;*      The System VM's Control Block should be set up with the initial
;*      state of the VxD.  Since the System VM has already been created
;*      calls such as Simulate_Int or Exec_Int are allowed.
;*
;*  ENTRY:
;*      EBX     :       VM Handle.
;*
;*  EXIT:
;*      Carry clear if successful.  Set if fail--this will keep this
;*      VxD from loading.
;*
;*  NOTES:
;*

BeginProc VIWD_Dyn_Device_Init
 
	VMMcall _Allocate_Device_CB_Area, <<SIZE INTERWAV_CB_DATA>, 0>
	test    eax, eax
	jnz     short IW_DDI_CB_OK

	Debug_Out "VIWD_Dyn_Device_Init: _Allocate_Device_CB_Area failed!"
	VMMcall Fatal_Memory_Error

IW_DDI_CB_OK:
	mov     [INTERWAV_CB_Offset], eax        ; gotta keep this around
	ret
EndProc VIWD_Dyn_Device_Init


BeginDoc
;** VIWD_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.
;*
;*  EXIT:
;*      Client:
;*              Carry clear     :  success
;*              Carry set       :  hosed
;*
;*  NOTES:
;*
;** cjp *
EndDoc

BeginProc VIWD_API_Proc

	;; a short word from our sponsor

	movzx   eax, [ebp.Client_DX]       ; function #
IFDEF NORMAL
	Trace_Out "VIWD_API_Proc: VM #EBX Function #EAX"
ENDIF
	cmp     ax, IW_API_MAX             ; a valid service?
	jae     short VIWD_API_Failed
	jmp     IW_API_TABLE[ eax * 4 ]

	public VIWD_API_Success
VIWD_API_Success:
IFDEF NORMAL
        Trace_Out "VIWD_API_Proc: Success!  VM #EBX"
ENDIF
	and     [ebp.Client_EFlags], NOT CF_Mask
	jmp     short VIWD_API_Exit

	public VIWD_API_Failed                               
VIWD_API_Failed:

;       Trace_Out "VIWD_API_Proc: Failed!  VM #EBX"

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

VIWD_API_Exit:
	ret

EndProc VIWD_API_Proc

;***************************************************************************
;
;   VIWD_System_Exit
;
;   Description: mask the irq we unmasked on initialization
;
;===========================================================================

BeginProc VIWD_System_Exit

	clc
	ret

EndProc VIWD_System_Exit

VxD_CODE_ENDS


	end
