⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fspsgdi.asm

📁 汇编编程艺术
💻 ASM
字号:
		.286
		page	58, 132
		name	FSPSGDI
		title	FSPSGDI (CH Products Standard Game Device Interface).

; CHSGDI.EXE
;
;	Usage:
;		CHSDGI	{LEFT}
;
; This program loads a TSR which patches INT 15 so arbitrary game programs
; can read the CH Products FlightStick Pro joystick in a portable fashion.


wp		equ	<word ptr>
byp		equ	<byte ptr>



; We need to load cseg in memory before any other segments!

cseg		segment	para public 'code'
cseg		ends


; Initialization code, which we do not need except upon initial load,
; goes in the following segment:

Initialize	segment	para public 'INIT'
Initialize	ends

; UCR Standard Library routines which get dumped later on.

		.xlist
		include		stdlib.a
		includelib	stdlib.lib
		.list

sseg		segment	para stack 'stack'
sseg		ends

zzzzzzseg	segment	para public 'zzzzzzseg'
zzzzzzseg	ends



CSEG		segment	para public 'CODE'
		assume	cs:cseg, ds:nothing

Int15Vect	dd	0

PSP		dw	?

; Port addresses for a typical joystick card:

JoyPort		equ	201h
JoyTrigger	equ	201h


CurrentReading	dw	0

Pot		struc
PotMask		db	0			;Pot mask for hardware.
DidCal		db	0			;Is this pot calibrated?
min		dw	5000			;Minimum pot value
max		dw	0			;Max pot value
center		dw	0			;Pot value in the middle
Pot		ends

Pot0		Pot	<1>
Pot1		Pot	<2>
Pot3		Pot	<8>


; SwapButtons-	0 if we should use normal flightstick pro buttons,
;		1 if we should swap the left and right buttons.

SwapButtons	byte	0

; SwBits- the four bit input value from the Flightstick Pro selects one
;	  of the following bit patterns for a given switch position.

SwBits		byte	10h		;Sw4
		byte	0		;NA
		byte	0		;NA
		byte	0		;NA
		byte	40h		;Sw6
		byte	0		;NA
		byte	0		;NA
		byte	4		;Sw 2

		byte	80h		;Sw 7
		byte	0		;NA
		byte	0		;NA
		byte	8		;Sw 3
		byte	20h		;Sw 5
		byte	2		;Sw 1
		byte	1		;Sw 0
		byte	0		;NA

SwBitsL		byte	10h		;Sw4
		byte	0		;NA
		byte	0		;NA
		byte	0		;NA
		byte	40h		;Sw6
		byte	0		;NA
		byte	0		;NA
		byte	4		;Sw 2

		byte	80h		;Sw 7
		byte	0		;NA
		byte	0		;NA
		byte	2		;Sw 3
		byte	20h		;Sw 5
		byte	8		;Sw 1
		byte	1		;Sw 0
		byte	0		;NA



; The IDstring address gets passed back to the caller on a testpresence
; call.  The four bytes before the IDstring must contain the serial number
; and current driver number.

SerialNumber	db	0,0,0
IDNumber	db	0
IDString	db	"CH Products:Flightstick Pro",0
		db	"Written by Randall Hyde",0






;============================================================================
;
; ReadPots- AH contains a bit mask to determine which pots we should read.
;	    Bit 0 is one if we should read pot 0, bit 1 is one if we should
;	    read pot 1, bit 3 is one if we should read pot 3.  All other bits
;	    will be zero.
;
;	This code returns the pot values in SI, BX, BP, and DI for Pot 0, 1,
;	2, & 3.
;

ReadPots	proc	near
		sub	bp, bp
		mov	si, bp
		mov	di, bp
		mov	bx, bp

; Wait for pots to finish any past junk:

		mov	dx, JoyPort
		out	dx, al		;Trigger pots
		mov	cx, 400h
Wait4Pots:	in	al, dx
		and	al, 0Fh
		loopnz	Wait4Pots

; Okay, read the pots:

		mov	dx, JoyTrigger
		out	dx, al		;Trigger pots
		mov	dx, JoyPort
		mov	cx, 8000h	;Don't let this go on forever.
PotReadLoop:	in	al, dx
		and	al, ah
		jz	PotReadDone
		shr	al, 1
		adc	si, 0
		shr	al, 1
		adc	bp, 0
		shr	al, 2
		adc	di, 0
		loop	PotReadLoop
PotReadDone:
		ret
ReadPots	endp



;----------------------------------------------------------------------------
;
; Normalize- 	BX contains a pointer to a pot structure, AX contains
;		a pot value.  Normalize that value according to the
;		calibrated pot.
;
; Note: DS must point at cseg before calling this routine.


		assume	ds:cseg
Normalize	proc	near
		push	cx

; Sanity check to make sure the calibration process went okay.

		cmp	[bx].Pot.DidCal, 0
		je	BadNorm
		mov	dx, [bx].Pot.Center
		cmp	dx, [bx].Pot.Min
		jbe	BadNorm
		cmp	dx, [bx].Pot.Max
		jae	BadNorm

; Clip the value if it is out of range.

		cmp	ax, [bx].Pot.Min
		ja	MinOkay
		mov	ax, [bx].Pot.Min
MinOkay:

		cmp	ax, [bx].Pot.Max
		jb	MaxOkay
		mov	ax, [bx].Pot.Max
MaxOkay:

; Scale this guy around the center:

		cmp	ax, [bx].Pot.Center
		jb	Lower128

; Scale in the range 128..255 here:

		sub	ax, [bx].Pot.Center
		mov	dl, ah		;Multiply by 128
		mov	ah, al
		mov	dh, 0
		mov	al, dh
		shr	dl, 1
		rcr	ax, 1
		mov	cx, [bx].Pot.Max
		sub	cx, [bx].Pot.Center
		jz	BadNorm		;Prevent division by zero.
		div	cx		;Compute normalized value.
		add	ax, 128		;Scale to range 128..255.
		cmp	ah, 0
		je	NormDone
		mov	ax, 0ffh	;Result must fit in 8 bits!
		jmp	NormDone

; Scale in the range 0..127 here:

Lower128:	sub	ax, [bx].Pot.Min
		mov	dl, ah		;Multiply by 128
		mov	ah, al
		mov	dh, 0
		mov	al, dh
		shr	dl, 1
		rcr	ax, 1
		mov	cx, [bx].Pot.Center
		sub	cx, [bx].Pot.Min
		jz	BadNorm
		div	cx		;Compute normalized value.
		cmp	ah, 0
		je	NormDone
		mov	ax, 0ffh	;Result must fit in 8 bits!
		jmp	NormDone

BadNorm:	sub	ax, ax
NormDone:	pop	cx
		ret
Normalize	endp
		assume	ds:nothing







;============================================================================
; INT 15h handler functions.
;============================================================================
;
; Although these are defined as near procs, they are not really procedures.
; The MyInt15 code jumps to each of these with BX, a far return address, and
; the flags sitting on the stack.  Each of these routines must handle the
; stack appropriately.
;
;----------------------------------------------------------------------------
; BIOS- Handles the two BIOS calls, DL=0 to read the switches, DL=1 to
;	read the pots.  For the BIOS routines, we'll ignore the cooley
;	switch (the hat) and simply read the other four switches.

BIOS		proc	near
		cmp	dl, 1		;See if switch or pot routine.
		jb	Read4Sw
		je	ReadBIOSPots
		pop	bx
		jmp	cs:Int15Vect	;Let someone else handle it!

Read4Sw:	push	dx
		mov	dx, JoyPort
		in	al, dx
		shr	al, 4
		mov	bl, al
		mov	bh, 0
		cmp	cs:SwapButtons, 0
		je	DoLeft2
		mov	al, cs:SwBitsL[bx]
		jmp	SBDone

DoLeft2:	mov	al, cs:SwBits[bx]
SBDone:		rol	al, 4		;Put Sw0..3 in upper bits and make
		not	al		; 0=switch down, just like game card.
		pop	dx
		pop	bx
		iret

ReadBIOSPots:	pop	bx		;Return a value in BX!
		push	si
		push	di
		push	bp
		mov	ah, 0bh
		call	ReadPots
		mov	ax, si
		mov	bx, bp
		mov	dx, di
		sub	cx, cx
		pop	bp
		pop	di
		pop	si
		iret
BIOS		endp






;----------------------------------------------------------------------------
;
; ReadPot-	On entry, DL contains a pot number to read.
;		Read and normalize that pot and return the result in AL.

		assume	ds:cseg
ReadPot		proc	near
;;;;;;;;;;	push	bx		;Already on stack.
		push	ds
		push	cx
		push	dx
		push	si
		push	di
		push	bp

		mov	bx, cseg
		mov	ds, bx

		cmp	dl, 0
		jne	Try1
		mov	ah, Pot0.PotMask
		call	ReadPots
		lea	bx, Pot0
		mov	ax, si
		call	Normalize
		jmp	GotPot

Try1:		cmp	dl, 1
		jne	Try3
		mov	ah, Pot1.PotMask
		call	ReadPots
		lea	bx, Pot1
		mov	ax, bp
		call	Normalize
		jmp	GotPot

Try3:		cmp	dl, 3
		jne	BadPot
		mov	ah, Pot3.PotMask
		call	ReadPots
		lea	bx, Pot3
		mov	ax, di
		call	Normalize
		jmp	GotPot

BadPot:		sub	ax, ax		;Question: Should we pass this on
					; or just return zero?
GotPot:		pop	bp
		pop	di
		pop	si
		pop	dx
		pop	cx
		pop	ds
		pop	bx
		iret
ReadPot		endp
		assume	ds:nothing


;----------------------------------------------------------------------------
;
; ReadRaw-	On entry, DL contains a pot number to read.
;		Read that pot and return the unnormalized result in AL.

		assume	ds:cseg
ReadRaw		proc	near
;;;;;;;;;;	push	bx		;Already on stack.
		push	ds
		push	cx
		push	dx
		push	si
		push	di
		push	bp

		mov	bx, cseg
		mov	ds, bx

		cmp	dl, 0
		jne	Try1
		mov	ah, Pot0.PotMask
		call	ReadPots
		mov	ax, si
		jmp	GotPot

Try1:		cmp	dl, 1
		jne	Try3
		mov	ah, Pot1.PotMask
		call	ReadPots
		mov	ax, bp
		jmp	GotPot

Try3:		cmp	dl, 3
		jne	BadPot
		mov	ah, Pot3.PotMask
		call	ReadPots
		mov	ax, di
		jmp	GotPot

BadPot:		sub	ax, ax		;Question: Should we pass this on
					; or just return zero?
GotPot:		pop	bp
		pop	di
		pop	si
		pop	dx
		pop	cx
		pop	ds
		pop	bx
		iret
ReadRaw		endp
		assume	ds:nothing


;----------------------------------------------------------------------------
; Read4Pots-	Reads pots zero, one, two, and three returning their
;		values in AL, AH, DL, and DH.  Since the flightstick
;		Pro doesn't have a pot 2 installed, return zero for
;		that guy.

Read4Pots	proc	near
;;;;;;;;;;;	push	bx		;Already on stack
		push	ds
		push	cx
		push	si
		push	di
		push	bp

		mov	dx, cseg
		mov	ds, dx

		mov	ah, 0bh		;Read pots 0, 1, and 3.
		call	ReadPots

		mov	ax, si
		lea	bx, Pot0
		call	Normalize
		mov	cl, al

		mov	ax, bp
		lea	bx, Pot1
		call	Normalize
		mov	ch, al

		mov	ax, di
		lea	bx, Pot3
		call	Normalize
		mov	dh, al		;Pot 3 value.
		mov	ax, cx		;Pots 0 and 1.
		mov	dl, 0		;Pot 2 is non-existant.

		pop	bp
		pop	di
		pop	si
		pop	cx
		pop	ds
		pop	bx
		iret
Read4Pots	endp




;----------------------------------------------------------------------------
; CalPot-	Calibrate the pot specified by DL.  On entry, AL contains
;		the minimum pot value (it better be less than 256!), BX
;		contains the maximum pot value, and CX contains the centered
;		pot value.

		assume	ds:cseg
CalPot		proc	near
		pop	bx		;Retrieve maximum value
		push	ds
		push	si
		mov	si, cseg
		mov	ds, si

; Sanity check on parameters, sort them in ascending order:

		mov	ah, 0
		cmp	bx, cx
		ja	GoodMax
		xchg	bx, cx
GoodMax:	cmp	ax, cx
		jb	GoodMin
		xchg	ax, cx
GoodMin:	cmp	cx, bx
		jb	GoodCenter
		xchg	cx, bx
GoodCenter:


; Okay, figure out who were supposed to calibrate:

		lea	si, Pot0
		cmp	dl, 1
		jb	DoCal
		lea	si, Pot1
		je	DoCal
		cmp	dl, 3
		jne	CalDone
		lea	si, Pot3

DoCal:		mov	[si].Pot.min, ax
		mov	[si].Pot.max, bx
		mov	[si].Pot.center, cx
		mov	[si].Pot.DidCal, 1
CalDone:	pop	si
		pop	ds
		iret
CalPot		endp
		assume	ds:nothing


;----------------------------------------------------------------------------
; TestCal-	Just checks to see if the pot specified by DL has already
;		been calibrated.

		assume	ds:cseg
TestCal		proc	near
;;;;;;;;	push	bx		;Already on stack
		push	ds
		mov	bx, cseg
		mov	ds, bx

		sub	ax, ax		;Assume no calibration
		lea	bx, Pot0
		cmp	dl, 1
		jb	GetCal
		lea	bx, Pot1
		je	GetCal
		cmp	dl, 3
		jne	BadCal
		lea	bx, Pot3

GetCal:		mov	al, [bx].Pot.DidCal
		mov	ah, 0
BadCal:		pop	ds
		pop	bx
		iret
TestCal		endp
		assume	ds:nothing


;----------------------------------------------------------------------------
;
; ReadSw-	Reads the switch whose switch number appears in DL.

SwTable		byte	11100000b, 11010000b, 01110000b, 10110000b
		byte	00000000b, 11000000b, 01000000b, 10000000b

SwTableL	byte	11100000b, 10110000b, 01110000b, 11010000b
		byte	00000000b, 11000000b, 01000000b, 10000000b

ReadSw		proc	near
;;;;;;;		push	bx		;Already on stack
		mov	bl, dl		;Save switch to read.
		mov	bh, 0
		mov	dx, JoyPort
		in	al, dx
		and  	al, 0f0h
		cmp	cs:SwapButtons, 0
		je	DoLeft0
		cmp	al, cs:SwTableL[bx]
		jne	NotDown
		jmp	IsDown

DoLeft0:	cmp	al, cs:SwTable[bx]
		jne	NotDown

IsDown:		mov	ax, 1
		pop	bx
		iret

NotDown:	sub	ax, ax
		pop	bx
		iret
ReadSw		endp


;----------------------------------------------------------------------------
;
; Read16Sw-	Reads all eight switches and returns their values in AX.

Read16Sw	proc	near
;;;;;;;;	push	bx		;Already on stack
		mov	ah, 0		;Switches 8-15 are non-existant.
		mov	dx, JoyPort
		in	al, dx
		shr	al, 4
		mov	bl, al
		mov	bh, 0
		cmp	cs:SwapButtons, 0
		je	DoLeft1
		mov	al, cs:SwBitsL[bx]
		jmp	R8Done

DoLeft1:	mov	al, cs:SwBits[bx]
R8Done:		pop	bx
		iret
Read16Sw	endp


;****************************************************************************
;
; MyInt15-	Patch for the BIOS INT 15 routine to control reading the
;		joystick.

MyInt15		proc	far
		push	bx
		cmp	ah, 84h			;Joystick code?
		je	DoJoystick
OtherInt15:	pop	bx
		jmp	cs:Int15Vect

DoJoystick:	mov	bh, 0
		mov	bl, dh
		cmp	bl, 80h
		jae	VendorCalls
		cmp	bx, JmpSize
		jae	OtherInt15
		shl	bx, 1
		jmp	wp cs:jmptable[bx]

jmptable	word	BIOS
		word	ReadPot, Read4Pots, CalPot, TestCal
		word	ReadRaw, OtherInt15, OtherInt15
		word	ReadSw, Read16Sw
JmpSize		=	($-jmptable)/2


; Handle vendor specific calls here.

VendorCalls:	je	RemoveDriver
		cmp	bl, 81h
		je	TestPresence
		pop	bx
		jmp	cs:Int15Vect

; TestPresence- Returns zero in AX and a pointer to the ID string in ES:BX

TestPresence:	pop	bx		;Get old value off stack.
		sub	ax, ax
		mov	bx, cseg
		mov	es, bx
		lea	bx, IDString
		iret

; RemoveDriver- If there are no other drivers loaded after this one in
;		memory, disconnect it and remove it from memory.

RemoveDriver:
		push	ds
		push	es
		push	ax
		push	dx

		mov	dx, cseg
		mov	ds, dx

; See if we're the last routine patched into INT 15h

		mov	ax, 3515h
		int	21h
		cmp	bx, offset MyInt15
		jne	CantRemove
		mov	bx, es
		cmp	bx, wp seg MyInt15
		jne	CantRemove

		mov	ax, PSP			;Free the memory we're in
		mov	es, ax
		push	es
		mov	ax, es:[2ch] 		;First, free env block.
		mov	es, ax
		mov	ah, 49h
		int	21h
;
		pop	es			;Now free program space.
		mov	ah, 49h
		int	21h

		lds	dx, Int15Vect		;Restore previous int vect.
		mov	ax, 2515h
		int	21h

CantRemove:	pop	dx
		pop	ax
		pop	es
		pop	ds
		pop	bx
		iret
MyInt15		endp
cseg		ends



; The following segment is tossed when this code goes resident.

Initialize	segment	para public 'INIT'
		assume	cs:Initialize, ds:cseg
Main		proc
		mov	ax, cseg		;Get ptr to vars segment
		mov	es, ax
		mov	es:PSP, ds		;Save PSP value away
		mov	ds, ax

		mov	ax, zzzzzzseg
		mov	es, ax
		mov	cx, 100h
		meminit2

		print
		byte	"帜哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -