📄 vmp3d.asm
字号:
;/////////////////////////////////////////////////////////////////////////////
;// vmp3d.asm
;//
;// Virtual MPEG Audio Layer3 Device module (link with MP3 Decoder module)
;//
;// 25/10/1999 fOSSiL Initial version
;// 12/11/1999 fOSSiL Switched to VPICD_Get_Version start-point
;// and added better fault-recovery
;// 2000/01/15 The Owl nasm port
;// 2000/01/16 The Owl started to add playing related services
;// 2000/01/17 Fossil fixed Trace_Out macros, intersegment relocs
;// 2000/01/17 The Owl fixed bugs introduced in the nasm port ;-)
;// 2000/01/18 The Owl added services
;// 2000/01/20 The Owl rewrote MMSYSTEM and AppyTime event handling
;// 2000/01/21 The Owl fixed VMP3D_Play_Prev/Next
;// 2000/01/28 The Owl init fails properly when VDSPD doesn't load
;// 2000/06/21 The Owl dword aligned data variables
%include "util.mac"
%include "vxdn.inc"
%include "win32n.inc"
%include "vpicdi.inc"
%include "dma.inc"
%include "mp3dec.inc"
%include "vdspd.inc"
%include "fpu.inc"
%define Create_Service_Table_VMP3D
%include "vmp3d.inc"
global VMP3D_Control
bits 32
segment _LDATA
Declare_Virtual_Device VMP3D, 'VMP3D', 1, 0, VMP3D_Device_ID
segment _LTEXT
Begin_Control_Dispatch VMP3D
Control_Dispatch DEVICE_INIT,VMP3D_Device_Init
Control_Dispatch SYS_DYNAMIC_DEVICE_INIT,VMP3D_Device_Init
Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT,VMP3D_Device_Exit
Control_Dispatch W32_DEVICEIOCONTROL,VMP3D_W32_DeviceIoControl
End_Control_Dispatch
WAVE_FORMAT_PCM EQU 1
struc WaveFormatEx
wfmt_wFormatTag resw 1
wfmt_nChannels resw 1
wfmt_nSamplesPerSec resd 1
wfmt_nAvgBytesPerSec resd 1
wfmt_nBlockAlign resw 1
wfmt_wBitsPerSample resw 1
endstruc
;
; Global Data
;
segment _LDATA
align 4
Owner dd 0
IsPlaying db 0
align 4
OrgHwIntProc dd 0
OrgMaskIRQProc dd 0
DmaPhysAddr dd 0
DmaLinAddr dd 0
IrqNum dd 0
PicReg db 0
PicMask db 0
align 4
;VID VPICD_IRQ_Descriptor <5, VPICD_OPT_CAN_SHARE, DspHwIntProc>
IrqTab dd 0
hIrq dd 0
hDma dd 0
FileSize dd 0
FileLeft dd 0
BufAddr dd 0
BufPtr dd 0
cBlocks dd 0
CurBlock dd 0
ListBuf dd 0
ListPages dd 0
NextFile dd 0
MpegBuf dd 0
MpegPtr dd 0
MpegLastBytes dd 0
segment _SDATA
hMMLib dd 0
_hMMSem dd 0
waveOutOpen dd 0
waveOutClose dd 0
hMMmem dd 0
LinMMmem dd 0
IsBusy dd 0
segment _LDATA
MMwfe:
istruc WaveFormatEx
at wfmt_wFormatTag, dw WAVE_FORMAT_PCM
at wfmt_nChannels, dw 1
at wfmt_nSamplesPerSec, dd 22050
at wfmt_nAvgBytesPerSec, dd 22050
at wfmt_nBlockAlign, dw 1
at wfmt_wBitsPerSample, dw 8
iend
hMMWave dw 0
segment _LDATA
LastFrame:
istruc FrameInfo
iend
;
; Services
;
segment _LTEXT
VMP3D_Device_Init:
; load DSP vxd
mov edx, devname
mov eax, VXDLDR_INIT_DEVICE
VxDCall VXDLDR_LoadDevice
jnc .dsploaded
cmp eax, byte VXDLDR_ERR_DUPLICATE_DEVICE
jz .dsploaded
%if ADD_DEBUG = 1
Trace_Out "VDSPD did not load, code #EAX"
%endif
stc
retn
.dsploaded:
; Allocate a 64k DMA buffer for DSP
mov edx, DmaPhysAddr
; we need mem below 16Meg
; pages=16
; PG_SYS, VM=0
; align=64k
; minpage=0
; maxpage=1000h
; &Dma.PhysAddr
; PAGECONTIG|PAGEUSEALIGN|PAGEFIXED
VMMCall _PageAllocate, byte 16, byte PG_SYS, byte 0, byte 0fh, byte 0, dword 1000h, edx, dword PAGECONTIG + PAGEUSEALIGN + PAGEFIXED
cmp eax, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_Out "DMA buffer not alloced"
%endif
stc
retn
@@
mov [DmaLinAddr], eax
; Allocate a static MPEG buffer (8000h+2000h)
VMMCall _PageAllocate, byte 10, byte PG_SYS, byte 0, byte 0, byte 0, byte 0, byte 0, dword PAGEFIXED
cmp eax, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_Out "MPEG buffer not alloced"
%endif
jmp .cleanup1
@@
mov [MpegBuf], eax
; lookup VPICD irq tables
; we will lookup VPICD_Get_Version address,
; basing on the assumption that Get_Version is close
; to Virtualize_IRQ service
; and scan code from there for a specific MOV opcode
; (hopefully no one will hook Get_Version service)
mov eax, VPICD_Device_ID
VMMCall Get_DDB
cmp ecx, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_Out "Get_DBB failed"
%endif
jmp .cleanup2
@@
mov edi, [ecx + DDB_Service_Table_Ptr]
mov edi, dword [edi + (@@VPICD_Get_Version & 0xFFFF)*4]
; look for mov esi,<mem>[ecx*4] opcode
mov ecx, 1000h
mov al, 8bh
.again:
repne scasb
%if ADD_DEBUG = 1
Trace_OutNE "MOV pattern not found"
%endif
jne near .cleanup2
cmp word [edi], 8d34h
jne .again
mov edi, [edi+2] ; get irq table addr
cmp edi, 0C0000000h ; lame check, but at least something
jb near .cleanup3
; hopefully, this is the table of IRQStruct ptrs
mov [IrqTab], edi
mov edi, [edi] ; check table layout through IRQ0's structs
cmp edi, 0C0000000h ; lame check, but at least something
jb near .cleanup3
mov eax, [edi + VID_IRQCB.hIrqOwner]
cmp eax, 0C0000000h ; lame check, but at least something
jb .cleanup3
cmp dword [eax + VID_IRQ_Struct.DbgStr], 51524953h ; 'SIRQ'
jne .cleanup3
; init MPEG decoder
push dword ReadStreamData
call _MpegSetReadProc@4
; init AppyTime synchronization semaphore and load MMSYSTEM
cmp dword [hMMLib], byte 0
jne @F
VxDCall _SHELL_CallAtAppyTime, dword AppyLoadMMLib, byte 0, byte 0, byte 0
cmp eax, byte 0
jne @F
%if ADD_DEBUG = 1
Trace_Out "Init appy event-schedule failed"
%endif
jmp short .cleanup2
@@
; cmp dword [hMMSem], byte 0
; jne @F
;
; xor ecx, ecx
; VMMCall Create_Semaphore
;
;%if ADD_DEBUG = 1
; Trace_OutC "MM Semaphore not created"
;%endif
;
; jc .cleanup2
;
; mov [hMMSem], eax
;
;@@
%if ADD_DEBUG = 1
Trace_Out "MP3 vxd init success"
%endif
clc
retn
.cleanup3:
%if ADD_DEBUG = 1
Trace_Out "MOV pattern found, but VPICD structs are invalid or of unknown format"
%endif
.cleanup2:
; free MPEG buffer
VMMCall _PageFree, dword [MpegBuf], byte 0
.cleanup1:
; free DMA buffer
VMMCall _PageFree, dword [DmaLinAddr], byte 0
stc
retn
segment _LDATA
devname db 'vdspd.vxd',0
segment _LTEXT
AppyLoadMMLib:
; PROC C Public, dwRefData:DWORD, dwFlags:DWORD
cmp dword [hMMLib], byte 0
je @F
%if ADD_DEBUG = 1
Trace_Out "MMSYSTEM already loaded"
%endif
retn
@@
VxDCall _SHELL_LoadLibrary, dword libname
cmp eax, byte 32
jae @F
%if ADD_DEBUG = 1
Trace_Out "MMSYSTEM did not load, code #EAX"
%endif
retn
@@
mov [hMMLib], eax
VxDCall _SHELL_GetProcAddress, dword [hMMLib], dword fnopen
mov [waveOutOpen], eax
VxDCall _SHELL_GetProcAddress, dword [hMMLib], dword fnclose
mov [waveOutClose], eax
VxDCall _SHELL_LocalAllocEx, byte LMEM_FIXED, byte WaveFormatEx_size + 2, dword MMwfe
cmp eax, byte 0
jne @F
%if ADD_DEBUG = 1
Trace_Out "Cannot alloc 16bit mem"
%endif
retn
@@
mov [hMMmem], eax
mov [LinMMmem], edx
%if ADD_DEBUG = 1
Trace_Out "MMSYSTEM loaded at AppyTime"
%endif
retn
segment _LDATA
libname db 'MMSYSTEM',0
fnopen db 'WAVEOUTOPEN',0
fnclose db 'WAVEOUTCLOSE',0
segment _LTEXT
VMP3D_Device_Exit:
; cleanup DMA buffer
VMMCall _PageFree, dword [DmaLinAddr], byte 0
VMMCall _PageFree, dword [ListBuf], byte 0
VMMCall _PageFree, dword [MpegBuf], byte 0
xor eax, eax
clc
retn
;segment _PTEXT ; nasm intersegment relocs in same object are bad,
; better keep this in _LTEXT for now
;
; Win32 DeviceIoControl Dispatcher
;
VMP3D_W32_DeviceIoControl:
mov ecx, [esi + DIOCParams.dwIoControlCode]
mov ebx, [esi + DIOCParams.VMHandle]
mov ebp, [esi + DIOCParams.Internal1]
cmp ecx, byte DIOC_OPEN
jnz @F
cmp dword [Owner], byte 0
%if ADD_DEBUG = 1
Trace_OutNE "Device is already owned"
%endif
jne .err ; another VM has it
mov [Owner], ebx
VxDCall VDSPD_Get_IRQ
call HookIrq
%if ADD_DEBUG = 1
Trace_OutC "HookIrq failed"
%endif
jc .err
xor eax, eax
retn
@@
cmp ecx, byte DIOC_CLOSEHANDLE
jnz @F
mov eax, 1 ; release wave dev
call StopMpeg
call UnhookIrq
mov dword [Owner], 0
xor eax, eax
retn
@@
; get Function #
and ecx, 0x3FFC
cmp ecx,byte 4*10
ja .err
jmp [W32_API+ecx]
.err:
cmp eax, byte 1 ; eax cannot be == 0 on error
sbb eax, byte 0
retn
segment _LDATA
align 4
W32_API:
dd VMP3D_W32_DeviceIoControl.err
dd VMP3D_W32_DeviceIoControl.err ; W32_PlayWave
dd W32_SetList
dd W32_Play
dd W32_Stop
dd W32_Pause
dd W32_Resume
dd W32_GetMpegInfo
dd W32_GetStreamPtr
dd W32_SetStreamPtr
dd W32_GetStatusInfo
segment _LTEXT
W32_SetRetCode:
;Assume esi:PTR DIOCParams
cmp dword [esi + DIOCParams.cbOutBuffer], byte 4
jae @F
retn
@@
mov ecx, [esi + DIOCParams.lpvOutBuffer] ; write to out-buf
cmp ecx, byte 0
jz @F
mov [ecx], eax
@@
mov ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned
cmp ecx, byte 0
jz @F
mov dword [ecx], 4
@@
retn
W32_SetList:
;Assume esi:PTR DIOCParams
or eax, byte -1
mov edx, [esi + DIOCParams.cbInBuffer]
cmp edx, byte 4
jae @F
retn
@@
mov edi, [esi + DIOCParams.lpvInBuffer]
cmp edi, byte 0
jnz @F
retn
@@
bts dword [IsBusy], 0
jnc @F
retn
@@
add edx, 0fffh
shr edx, 12
cmp edx, [ListPages]
jbe .norealloc
mov [ListPages], edx
VMMCall _PageFree, dword [ListBuf], byte 0
VMMCall _PageAllocate, dword [ListPages], byte PG_SYS, byte 0, byte 0, byte 0, byte 0, byte 0, dword PAGEFIXED
cmp eax, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_OutZ "List buffer not alloced"
%endif
jmp short .err1
@@
mov [ListBuf], eax
.norealloc:
; copy list
mov ecx, [esi + DIOCParams.cbInBuffer]
push esi
mov esi, [ListBuf]
xchg esi, edi
rep movsb
pop esi
; update ptrs
mov edi, [ListBuf]
mov edx, edi
mov ecx, [edi]
add edi, byte 4
@@
add [edi], edx
add edi, byte 4
loop @B
mov dword [NextFile], 0
xor eax, eax
.svcret1:
call W32_SetRetCode
btr dword [IsBusy], 0
retn
.err1:
cmp eax, byte 1
sbb eax, byte 0
jmp short .svcret1
W32_Play:
;Assume esi:PTR DIOCParams
or eax, byte -1
cmp dword [esi + DIOCParams.cbInBuffer], byte 4
jae @F
retn
@@
mov edi, [esi + DIOCParams.lpvInBuffer]
cmp edi, byte 0
jnz @F
retn
@@
bts dword [IsBusy], 0
jnc @F
retn
@@
mov eax, [edi]
call SetIndex
jc @F
call PlayMpegIndex
jc @F
xor eax, eax
@@
call W32_SetRetCode
btr dword [IsBusy], 0
retn
W32_Stop:
;Assume esi:PTR DIOCParams
or eax, byte -1
cmp byte [IsPlaying], 0
jz @F
bts dword [IsBusy], 0
jc @F
mov eax, 1
call StopMpeg
xor eax, eax
btr dword [IsBusy], 0
@@
call W32_SetRetCode
retn
W32_Pause:
;Assume esi:PTR DIOCParams
or eax, byte -1
cmp byte [IsPlaying], 0
jz @F
VxDCall VDSPD_Pause
mov eax, -1
jc @F
xor eax, eax
@@
call W32_SetRetCode
retn
W32_Resume:
;Assume esi:PTR DIOCParams
or eax, byte -1
cmp byte [IsPlaying], 0
jz @F
VxDCall VDSPD_Resume
mov eax, -1
jc @F
xor eax, eax
@@
call W32_SetRetCode
retn
W32_GetStreamPtr:
;Assume esi:PTR DIOCParams
or eax, byte -1
cmp byte [IsPlaying], 0
jz @F
mov eax, [BufPtr]
@@
call W32_SetRetCode
cmp eax, byte 0
jl @F ; error
xor eax, eax
@@
retn
W32_SetStreamPtr:
;Assume esi:PTR DIOCParams
mov edi, [esi + DIOCParams.lpvInBuffer]
or eax, byte -1
cmp dword [esi + DIOCParams.cbInBuffer], byte 4
jb @F
cmp edi, byte 0
jz @F
cmp byte [IsPlaying], 0
jz @F
bts dword [IsBusy], 0
jc @F
mov eax, [edi]
call SetPtr
btr dword [IsBusy], 0
@@
call W32_SetRetCode
retn
W32_GetMpegInfo:
;Assume esi:PTR DIOCParams
mov edi, [esi + DIOCParams.lpvOutBuffer]
;Assume edi:PTR MpegInfo
or eax, byte -1
cmp dword [esi + DIOCParams.cbOutBuffer], byte MpegInfo_size
jb @F
cmp edi, byte 0
jz @F
cmp byte [IsPlaying], 0
jz @F
push esi
push edi
add edi, byte 4 ; sizeof MpegInfo.RetCode
mov ecx, (MpegInfo_size - 4) / 4
mov esi, LastFrame
rep movsd
pop edi
pop esi
mov eax, [FileSize]
mov [edi + MpegInfo.StreamSize], eax
xor eax, eax
@@
call W32_SetRetCode
mov ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned
cmp eax, byte 0
jnz @F
cmp ecx, byte 0
jz @F
mov dword [ecx], MpegInfo_size
@@
retn
W32_GetStatusInfo:
or eax, byte -1
cmp dword [esi + DIOCParams.cbOutBuffer], byte StatusInfo_size
jb .setretcode
mov edi, [esi + DIOCParams.lpvOutBuffer]
test edi, edi
jz .setretcode
push dword [NextFile]
pop dword [edi+StatusInfo.Track]
push dword [BufPtr]
pop dword [edi+StatusInfo.Progress],
mov al,[IsPlaying]
mov [edi+StatusInfo.IsPlaying], al
mov al,[IsBusy]
mov [edi+StatusInfo.IsBusy], al
xor eax, eax
.setretcode:
call W32_SetRetCode
mov ecx, [esi + DIOCParams.lpcbBytesReturned] ; write # of bytes returned
cmp eax, byte 0
jnz @F
cmp ecx, byte 0
jz @F
mov dword [ecx], StatusInfo_size
@@
retn
segment _LTEXT
SetPtr:
; EAX = index
cmp eax, [FileSize]
jb @F
or eax, byte -1
stc
retn
@@
; no interruptions now, please =)
pushfd
cli
mov [BufPtr], eax
mov ecx, [FileSize]
sub ecx, eax
mov [FileLeft], ecx
popfd
xor eax, eax
clc
retn
StopMpeg:
; EAX = 1 : release wave device
cmp byte [IsPlaying], 1
jnz @F
VxDCall VDSPD_Stop
mov byte [IsPlaying], 0
@@
cmp eax, byte 1
jnz @F
cmp word [hMMWave], 0
jz @F
VxDCall _SHELL_CallAtAppyTime, dword AppyWaveClose, byte 0, byte 0, byte 0
cmp eax, byte 0
%if ADD_DEBUG = 1
Trace_OutE "Let-go Wave appy event-schedule failed"
%endif
jz @F
; mov eax, [hMMSem]
; mov ecx, BLOCK_SVC_INTS | BLOCK_ENABLE_INTS
; VMMCall Wait_Semaphore
VMMCall _BlockOnID, dword hMMLib, dword BLOCK_SVC_INTS | BLOCK_ENABLE_INTS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -