Source file: /~heha/basteln/PC/LPTISA/lptisa.zip/LPTISA.ASM

;ISA-Port-Emulationstreiber für LPTISA-Adapter
	.386			;32bit-Segmente aktivieren
	include tvmm2.inc	;Generelles
;	include	debug2.inc	;wegen Debugging
;	include	vpicd.inc	;Interrupt-Controller
LPTISA_Device_ID	equ	4209h	;von Microsoft bestätigt:
;>You have been assigned a device ID of 4209h for your LPTISA.386 virtual
;>device.  This number is uniquely assigned to this device.
LPTISA_Major_Ver	equ	0
LPTISA_Minor_Ver	equ	1


;=============================
ifdef DEBUG
	%OUT	!Assembliere Debugversion!
endif

	locals	@@

Declare_Virtual_Device  LPTISA, LPTISA_Major_Ver, LPTISA_Minor_Ver,\
			LPTISA_Control_Proc, LPTISA_Device_ID,\
			3B800000h,LPTISA_API,LPTISA_API

;3C000000 ist die VPD_Init_Order des konkurrierenden VPD.VXD unter Windows95

;*********************************************************
;*** Obligatorischer VxD-Botschafts-Funktionsverteiler ***
;*********************************************************
VxD_Locked_Code_Seg
BeginProc LPTISA_Control_Proc
	Control_Dispatch Sys_Critical_Init, LPTISA_Init
	Control_Dispatch System_Exit, LPTISA_Exit
	Control_Dispatch 1bh, LPTISA_Dynamic_Init
	Control_Dispatch 1ch, LPTISA_Dynamic_Exit
	clc
	ret
EndProc LPTISA_Control_Proc
VxD_Locked_Code_ends

;********************************************************
;*** Residenter Datenbereich und Konstantendefinition ***
;********************************************************

MAXTRAP			equ	64	;Max. ISA-Zugriffsumlenkungen

TVxDData struc
 ;IrqHand	dd	?	;IRQ-Griff (IRQ7) - wozu? Windows macht's!
 LptBase	dd	378h	;Portadresse der LPT-Schnittstelle
 PatchAddr	dd	0	;Gepatchte Adresse im BIOS-Datenbereich
 IsaAddr	dw	?	;Merker für Adress-Flipflops (2x 74HC574)
 LptData	db	?	;Merker für Datenport (+0)
 LptCtrl	db	?	;Merker für Steuerport (+2)
 Trapped	dw	MAXTRAP dup (?)	;"Angezapfte" Portadressen
TVxDData ends

VxD_Locked_Data_Seg
VxDData		TVxDData	<>	;in <struc> für relative Adressierung
TrappedEnd	=	$
VxD_Locked_Data_Ends

;*******************************************
;** Real-Mode und Protected-Mode-API      **
;** (siehe Ralfbrownliste Int2F AX=1684h) **
;*******************************************

VxD_Locked_Code_Seg

BeginProc LPTISA_API
;Funktionen nur unter Win95+ verfügbar:
;* Portadresse hinzufügen (AH=2, DX=Adresse)
;* Portadresse löschen (AH=3, DX=Adresse)
;Funktionen in allen Windows verfügbar:
;* Liste der Portadressen abfragen (AH=1, AL=Nummer; PA: AX=Adresse, 0=frei)
;* Version von LPTISA.386 abfragen (AH=0)
	lea	edi,VxDData.Trapped
	mov	ecx,MAXTRAP
	mov	eax,[ebp.Client_EAX]	;AX laden
	cmp	ah,4
	jnc	@@err
	cmp	ah,2
	jnc	@@setres
	or	ah,ah
	jz	@@ver
	cmp	al,cl
	jnc	@@err
	movzx	eax,al
	mov	ax,[edi+eax*2]
	jmp	@@ax
@@ver:	mov	ax,LPTISA_Major_Ver*256+LPTISA_Minor_Ver
@@ax:	mov	[ebp.Client_AX],ax
	jmp	@@ok
@@setres:
	movzx	eax,[ebp.Client_DX]
	jnz	@@res
	or	eax,eax
	jz	@@err		;Null ist Fehler!
	xchg	edx,eax		;nach EDX schaffen
	xor	eax,eax
	repne	scasw		;Freie Stelle suchen
	jnz	@@err		;kein Platz
	lea	esi,IOHandler
	VMMcall	Install_IO_Handler	;Portzugriffe umlenken
	jmp	@@gem
@@res:
	or	eax,eax
	jz	@@err		;Null ist Fehler!
	repne	scasw		;Portadresse suchen
	jne	@@err		;nicht gefunden
	xchg	edx,eax		;nach EDX schaffen
	VMMCall	00010116h	;Remove_IO_Handler (Win95+)
	LD	edx,0		;Flags nicht verändern
@@gem:	jc	@@err		;ging schief
	mov	word ptr [edi-2],dx	;(ein- bzw.) austragen
@@ok:	BRES	[ebp.Client_Flags],CF_MASK
	ret
@@err:	BSET	[ebp.Client_Flags],CF_MASK
	ret
EndProc LPTISA_Api

;******************************************
;** Ein/Ausgabe-Anzapfung und -Umleitung **
;******************************************

;Steuerport-Bitbelegung
;Bit	Name	SubD	Inv	Verwendung	Aktiv-Bit
;0	/STB	1	ja	/IOWR		1
;1	/AF	14	ja	IORD		0 (wird invertiert)
;2	/INIT	16	nein	/RESET		0 (wird invertiert)
;3	/SEL	17	ja	/ALE		1 (wird invertiert)
;						0->1 lädt Low-Teil der Adresse
;						1->0 lädt High-Teil -"-
;4	/INT	-	-	-		1
;5	/INP	-	-	-		0 (Ausgabe, nicht rücklesbar!)
;Ruhezustand des Steuerports: x11110b (x je nach letztem Befehl)

;Um unnötige lahme ISA-Buszyklen zu vermeiden, werden diese nur ausgeführt,
;wenn sich irgendein Bit ändert. Der Unterprogrammaufruf kostet dagegen
;fast nichts, könnte aber durch Makros ersetzt werden...

BeginProc Put_Ctrl,No_Log
	cmp	al,[edi.LptCtrl]
	je	@@e
Put_Ctrl_:
	inc	edx
	inc	edx
	out	dx,al
	dec	edx
	dec	edx
	mov	[edi.LptCtrl],al
@@e:	ret
EndProc Put_Ctrl

BeginProc Put_Data,No_Log
	cmp	al,[edi.LptData]
	je	@@e
Put_Data_:
	out	dx,al
	mov	[edi.LptData],al
@@e:	ret
EndProc Put_Data

BeginProc Put_Addr
;Gibt die Adresse auf die Latches, sofern sie sich geändert hat
;PE: DX=Adresse
;PA: EDX=LPT-Basisadresse
;    CX=Adresse
;VR: ECX,EDX
	push	eax
	 mov	ecx,edx		;Adresse retten
	 mov	eax,[edi.LptBase]
	 xchg	eax,edx
	 xchg	[edi.IsaAddr],ax
	 cmp	cx,ax
	 je	@@e		;Keine Änderung!
	 mov	al,011110b	;auf AUSGABE schalten
	 call	Put_Ctrl
	 mov	al,ch
	 call	Put_Data	;High-Teil anlegen
	 mov	al,010110b
	 call	Put_Ctrl_	;High-Teil übernehmen, ALE=low, Adr. ungültig
	 mov	al,cl
	 call	Put_Data	;Low-Teil anlegen
	 mov	al,011110b
	 call	Put_Ctrl_	;Low-Teil übernehmen
@@e:	pop	eax
	ret
EndProc Put_Addr

;Trapserviceroutine für Portzugriffe auf die geschützten Adressen
;PE: EDX=Portadresse, ECX=Zugriffsart, EBX=VM-Griff, EAX=EA-Daten
BeginProc IOHandler,No_Log
	lea	edi,VxDData
	Dispatch_Byte_IO Fall_Through,@@o
	call	Put_Addr
	mov	al,111110b
	call	Put_Ctrl	;auf EINGABE schalten
	mov	al,111100b
	call	Put_Ctrl_	;/IORD aktivieren
	in	al,dx		;InByte lesen
	xchg	ecx,eax		;InByte retten
	 mov	al,111110b
	 call    Put_Ctrl_	;/IORD deaktivieren (EINGABE belassen)
	xchg	eax,ecx		;InByte liefern
	ret
@@o:
	call	Put_Addr
	xchg	ecx,eax
	 mov	al,011110b
	 call	Put_Ctrl	;auf AUSGABE schalten
	xchg	eax,ecx
	call	Put_Data	;OutByte anlegen
	mov	al,011111b
	call	Put_Ctrl_	;/IOWR aktivieren
	mov	al,011110b
	call    Put_Ctrl_	;/IOWR deaktivieren (AUSGABE belassen)
	ret
EndProc IOHandler


;*********************
;*** Exit-Funktion ***
;*********************

BeginProc LPTISA_Dynamic_Exit
	lea	edi,VxDData.Trapped
	LD	ecx,MAXTRAP
@@l:	movzx	edx,word ptr [edi]
	or	edi,edi
	jz	@@1
	VMMCall	00010116h	;Remove_IO_Handler
@@1:	inc	edi
	inc	edi
	loopd	@@l
LPTISA_Exit:
	lea	edi,VxDData
	mov	eax,[edi.LptBase]
	mov	edi,[edi.PatchAddr]
	or	edi,edi
	jz	@@e
	stosw			;zurückpatchen
@@e:	ret
EndProc LPTISA_Dynamic_Exit

VxD_Locked_Code_Ends

;******************************
;*** Installations-Funktion ***
;******************************
VxD_IData_Seg
;IrqDesc	VPICD_Irq_Descriptor <8,VPICD_Opt_Can_Share,OFFSET32 CmosIsr>
LPTISA$ db	"LPTISA",0
LPT$	db	"LPT",0
Ports$	db	"Ports",0
VxD_IData_Ends

VxD_ICode_Seg
BeginProc LPTISA_Dynamic_Init
;Nur LPT-Initialisierung, (noch) keine Traps
	lea	edi,VxDData
	mov	edx,[edi.LptBase]
	add	dx,402h
	mov	al,00100000b	;ECP-Schnittstelle in PS/2-Modus (rück)schalten
	out	dx,al
	LD	edx,-1
	call	Put_Addr	;Adresslatch (und Daten) auf FFFFh setzen
	mov	al,001010b
	call	Put_Ctrl_	;RESET und kein Interrupt
	mov	al,011110b
	jmp	Put_Ctrl_	;Default-Zustand
EndProc LPTISA_Dynamic_Init

BeginProc GetEntry
;Lese SYSTEM.INI-Eintrag in Form LPTx oder als Hexzahl (aus VDONGLE.386)
;PE: EDI=Key-String, ESI=LPTISA$
;PA: EAX=Portadresse
;    CY=1: kein oder ungültiger Eintrag
;VR: EAX,EDX
	VMMCall	Get_Profile_String
	jc	@@e		;Nicht gefunden? - Nicht auswerten!
	mov	eax,[edx]
	and	eax,00DFDFDFh	;Großbuchstaben!
	cmp	eax,'TPL'	;"LPT"?
	je	@@2		;ja
	VMMCall	Convert_Hex_String
	cmp	byte ptr [edx],1	;korrekt null-terminiert?
@@ecmc:	cmc
	ret
@@2:
	mov	al,[edx+3]	;Nummer...
	sub	al,'1'
	cmp	al,4
	jnc	@@ecmc
	movzx	eax,al
	movzx	eax,word ptr [408h+eax*2]	;LPT-Adresse...
	cmp	eax,1		;Null? (Wäre ein Fehler!)
@@e:	ret
EndProc GetEntry

BeginProc EditLpt
;entfernt LPT-Adresse aus BIOS-Datenbereich;
;vielleicht hält das Windows vom Direktzugriff ab?
	mov	edi,408h
	LD	ecx,3
	repne	scasw
	jne	@@e
	dec	edi
	dec	edi
	mov	[VxDData.PatchAddr],edi
	mov	word ptr [edi],0
@@e:	ret
EndProc EditLpt

BeginProc LPTISA_Init
;* Portadressen aus SYSTEM.INI holen
;* Ports trappen
;* LPT rücksetzen
	lea	esi,LPTISA$	;Sektion [LPTISA]
	lea	edi,LPT$	;Schlüssel LPT
	call	GetEntry	;Aus SYSTEM.INI ein Wert lesen
	jnc	@@01
	PUSHSTATE
	IDEAL			;Der Folgebefehl geht in MASM nicht...
	movzx	eax,[word 408h]	;LPT1
	POPSTATE
	or	eax,eax
	jz	@@00
@@01:	mov	[VxDData.LptBase],eax
	call	EditLpt
@@00:	lea	edi,Ports$
	VMMCall	Get_Profile_String	;Zeile lesen
	jc	@@x
	lea	edi,VxDData.Trapped
@@l1:	cmp	edi,OFFSET32 TrappedEnd
	je	@@x		;Liste voll!
	VMMCall	Convert_Hex_String
	stosw			;Adresse in Liste eintragen
	xchg	ecx,eax		;retten
@@y:	mov	al,[edx]	;Folge-Zeichen betrachten
	inc	edx
	or	al,al
	jz	@@x		;Ende der Liste
	cmp	al,'-'
	jnz	@@l1		;nächste IO-Adresse
	VMMCall	Convert_Hex_String
	xchg	ecx,eax		;ist eine Endadresse
@@l2:	inc	eax
	cmp	edi,OFFSET32 TrappedEnd
	je	@@x
	stosw
	cmp	eax,ecx		;bis zum Ende des Bereiches
	jb	@@l2
	inc	ecx		;falls jemand wirklich "280-288-289" schreibt
	jmp	@@y
@@x:
	call	LPTISA_Dynamic_Init

	add	edi,Trapped
	lea	esi,IOHandler
	LD	ecx,MAXTRAP
@@l:	movzx	edx,word ptr [edi]
	or	edx,edx
	jz	@@1
	VMMcall	Install_IO_Handler	;folgende Portzugriffe umlenken
	jnc	@@1
	mov	word ptr [edi],0
@@1:	inc	edi
	inc	edi
	loopd	@@l
@@e:
	ret
EndProc LPTISA_Init

VxD_ICode_Ends

	END
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded