home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 3 Comm
/
03-Comm.zip
/
SETCOM40.ZIP
/
SETCOM40.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-10-28
|
18KB
|
489 lines
TITLE SETCOM40 Device Driver for OS/2
PAGE 60, 132
COMMENT +
File: SETCOM40.ASM
File type: Microsoft Macro Assembler (MASM) Version 5.1 or higher
Author: John W. Cocula
Date: October, 1990
Purpose:
This device changes the BIOS COM ownership words if the BIOS
gets it wrong during POST.
+
.286c
.sall
DATA SEGMENT WORD PUBLIC 'DATA'
SUBTTL Device Driver Header
PAGE +
; ***********************************************************************
; * DEVICE HEADER *
; ***********************************************************************
PtrToNextHeader dd 0FFFFFFFFh ; Indicates loadable device driver
DeviceAttribute dw 1000000010000000b
; Bit 15 - Character device
; Bits 9-7 - OS/2 device driver
StrategyOffset dw CODE:Strategy ; Offset to the Strategy routine
IDCOffset dw 0 ; unused
DeviceName db 'SETCOM$$' ; Name of the device
ReservedBlock2 db 8 dup (0) ; Reserved words
; ***********************************************************************
; * DEVHLP SUPPORT *
; ***********************************************************************
.XLIST
;
; These constants define the DevHlp commands:
;
;DevHlp_SchedClockAddr EQU 0 ; 0h Get system clock routine
;DevHlp_DevDone EQU 1 ; 1h Device I/O Complete
;DevHlp_Yield EQU 2 ; 2h Yield the CPU
;DevHlp_TCYield EQU 3 ; 3h Yield the CPU to time-critical
;DevHlp_Block EQU 4 ; 4h Block thread on event
;DevHlp_Run EQU 5 ; 5h Unblock thread
;DevHlp_SemRequest EQU 6 ; 6h Claim a semaphore
;DevHlp_SemClear EQU 7 ; 7h Release a semaphore
;DevHlp_SemHandle EQU 8 ; 8h Get a semaphore handle
;DevHlp_PushReqPacket EQU 9 ; 9h Add request to list
;DevHlp_PullReqPacket EQU 10 ; Ah Remove request from list
;DevHlp_PullParticular EQU 11 ; Bh Remove a specific request from list
;DevHlp_SortReqPacket EQU 12 ; Ch Insert request in sorted order to list
;DevHlp_AllocReqPacket EQU 13 ; Dh Get a request packet
;DevHlp_FreeReqPacket EQU 14 ; Eh Free request packet
;DevHlp_QueueInit EQU 15 ; Fh Initialize character queue
;DevHlp_QueueFlush EQU 16 ;10h Clear character queue
;DevHlp_QueueWrite EQU 17 ;11h Put a char in the queue
;DevHlp_QueueRead EQU 18 ;12h Get a char from the queue
;DevHlp_Lock EQU 19 ;13h Lock segment
;DevHlp_Unlock EQU 20 ;14h Unlock segment
;DevHlp_PhysToVirt EQU 21 ;15h Map physical address to virtual
;DevHlp_VirtToPhys EQU 22 ;16h Map virtual-to-physical address
DevHlp_PhysToUVirt EQU 23 ;17h Map physical-to-user virtual
;DevHlp_AllocPhys EQU 24 ;18h Allocate physical memory
;DevHlp_FreePhys EQU 25 ;19h Free physical memory
;DevHlp_SetROMVector EQU 26 ;1Ah Set software interrupt vector
;DevHlp_SetIRQ EQU 27 ;1Bh Set a hardware interrupt handler
;DevHlp_UnSetIRQ EQU 28 ;1Ch Reset a hardware interrupt handler
;DevHlp_SetTimer EQU 29 ;1Dh Set timer request handler
;DevHlp_ResetTimer EQU 30 ;1Eh Remove a timer handler
;DevHlp_MonitorCreate EQU 31 ;1Fh Create a monitor
;DevHlp_Register EQU 32 ;20h Install a monitor
;DevHlp_DeRegister EQU 33 ;21h Remove a monitor
;DevHlp_MonWrite EQU 34 ;22h Pass data records to monitor
;DevHlp_MonFlush EQU 35 ;23h Remove all data from stream
;DevHlp_GetDOSVar EQU 36 ;24h Return pointer to DOS variable
;DevHlp_SendEvent EQU 37 ;25h Indicate an event
;DevHlp_ROMCritSection EQU 38 ;26h ROM BIOS critical section
;DevHlp_VerifyAccess EQU 39 ;27h Verify access to memory
;DevHlp_AllocGDTSelector EQU 45 ;2Dh Allocate GDT selectors
;DevHlp_PhysToGDTSelector EQU 46 ;2Eh Map physical to virtual address
;DevHlp_RealToProt EQU 47 ;2Fh Real Mode to Protect Mode
;DevHlp_ProtToReal EQU 48 ;30h Protect Mode to Real Mode
;DevHlp_EOI EQU 49 ;31h Issue an End-Of-Interrupt
;DevHlp_UnPhysToVirt EQU 50 ;32h Mark PhysToVirt complete
;DevHlp_TickCount EQU 51 ;33h Modify timer
;DevHlp_GetLIDEntry EQU 52 ;34h Get Logical ID
;DevHlp_FreeLIDEntry EQU 53 ;35h Release Logical ID
;DevHlp_ABIOSCall EQU 54 ;36h Invoke ABIOS function
;DevHlp_ABIOSCommonEntry EQU 55 ;37h Invoke ABIOS Common Entry Point
;
; This macro simplifies calling a DevHlp service by doing a load of the
; function code into DL and calling pfnDevHlp.
;
@DevHlp MACRO name
mov dl, DevHlp_&name
call pfnDevHlp
ENDM
.LIST
SUBTTL Structures/Codes for Request Packets
PAGE +
; ***********************************************************************
; * REQUEST PACKET STRUCTURE *
; ***********************************************************************
PKTMAX EQU 18 ; Maximum size of packet
PacketStruc STRUC
PktLen db ? ; Length in bytes of packet
PktUnit db ? ; Subunit number of block device
PktCmd db ? ; Command code
PktStatus dw ? ; Status word
PktDOSLink dd ? ; Reserved
PktDevLink dd ? ; Device multiple-request link
PktData db PKTMAX dup (?) ; Data pertaining to specific packet
PacketStruc ENDS
; ***********************************************************************
; * CODES FOR STATUS OF REQUEST PACKET *
; ***********************************************************************
; Bit positions in Status field:
StatRecord RECORD StatError:1,StatDevError:1,StatRes:4,StatBusy:1,\
StatDone:1,StatErrCode:8
; Error Codes:
StatWrProtVio EQU 00h ; WRITE PROTECT VIOLATION
StatUnknownCmd EQU 03h ; UNKNOWN COMMAND
StatGenFailure EQU 0Ch ; GENERAL FAILURE
StatCharIOIntd EQU 11h ; CHARACTER I/O INTERRUPTED
StatMonNotSupp EQU 12h ; MONITORS NOT SUPPORTED
; ***********************************************************************
; * POINTER CONSTANTS FOR REQUEST PACKET *
; ***********************************************************************
Packet EQU ES:[BX]
; Offsets into packet for INIT and READ/WRITE commands:
InitpEnd EQU DWORD PTR PktData+1 ; Pointer to freemem after dev
InitArgs EQU DWORD PTR PktData+5 ; Pointer to CONFIG.SYS args
; ***********************************************************************
; * DATA USED BY THE STRATEGY ROUTINE *
; ***********************************************************************
fbError db 0 ; Error flag used to signal to the Strategy
; routine a return with error from another
; subroutine.
END_OF_DATA EQU $
pfnDevHlp dd ? ; Holds address of the DevHlp function entry
ArgPtr dd ? ; Holds address of CONFIG.SYS argument string
com1 dw 03F8h ; default comm port values
com2 dw 02F8h ; default comm port values
InitBanner db 13,10,'SETCOM40 Device Driver Version 1.0'
Banner_strlen EQU $-InitBanner
bad_string db 13,10,' Bad '
bad_strlen EQU $-bad_string
specified_string db ' value specified.',13,10
specified_strlen EQU $-specified_string
invparam_string db 13,10,' Invalid parameter specified',13,10
invparam_strlen EQU $-invparam_string
com1_string db 'COM1='
com1_strlen EQU $-com1_string
com2_string db 'COM2='
com2_strlen EQU $-com2_string
DATA ENDS
CODE SEGMENT WORD PUBLIC 'CODE'
ASSUME CS:CODE, DS:DATA, ES:NOTHING
; ***********************************************************************
; * STRATEGY ROUTINE *
; * *
; * Far procedure Strategy gets the request packet and based on its *
; * command code branches to the appropriate subroutine. Upon return *
; * from the subroutine, the request is signalled serviced with or *
; * without error. *
; ***********************************************************************
Strategy PROC FAR
push es ; save the pointers to the request packet
push bx
mov al, BYTE PTR Packet.PktCmd
cmp al, 0 ; Command code is moved into al
; If index larger than those supported
jne UNSUPPORTED ; Jump to indicate that the command is
; unsupported
mov fbError, 0 ; Zero out the fbError flag prior to the call
call INIT ; Call only entry point supported.
pop bx ; Restore the pointers to the request packet
pop es
cmp fbError, 0 ; Upon return, check if subroutine returned
; an error
jz ERROR_FREE ; If no error, jump to signal devdone
or Packet.PktStatus, MASK StatError + StatGenFailure
; Set the error condition in the Req Packet
; Set the error to General Failure
or Packet.PktStatus, MASK StatDone
jmp FIN
ERROR_FREE:
mov Packet.PktStatus, MASK StatDone
jmp FIN
UNSUPPORTED:
pop bx ; Retrieve the pushed values of bx and es
pop es
or Packet.PktStatus, MASK StatError + StatUnknownCmd
FIN:
ret
Strategy ENDP
SUBTTL Initialization Code
page +
END_OF_CODE EQU $
; ***********************************************************************
; * Initialization code is placed at the end of the code segment so it *
; * can go away once initialization has been done. *
; ***********************************************************************
SUBTTL Initialization Code
PAGE +
.XLIST ; Suppress listing of files
INCL_VIO EQU 1
INCLUDE OS2.INC
.LIST
@SayBad MACRO string, strlen
@VioWrtTTy bad_string, bad_strlen, 0
@VioWrtTTy string, strlen, 0
@VioWrtTTy specified_string, specified_strlen, 0
ENDM
INT_PASSED EQU 0
INT_ERROR EQU -1
; ***********************************************************************
; * INIT ROUTINE *
; * *
; * INIT procedure is placed at the end of the code so it can go away *
; * once initialization has been done. *
; ***********************************************************************
INIT PROC NEAR
; ========================================================================
; Save the pointer to the DevHlp routines passed in the request packet.
; ========================================================================
mov ax, WORD PTR Packet.InitpEnd ; Save pointer to DevHlp
mov WORD PTR pfnDevHlp, ax
mov ax, WORD PTR Packet.InitpEnd+2
mov WORD PTR pfnDevHlp+2, ax
mov ax, WORD PTR Packet.InitArgs ; Save the far pointer to
mov WORD PTR ArgPtr, ax ; the CONFIG.SYS arguments
mov ax, WORD PTR Packet.InitArgs+2
mov WORD PTR ArgPtr+2, ax
push es ; save ptr to request packet
push bx
; ------------------------------------------------------------------------
; Say hi.
; ------------------------------------------------------------------------
@VioWrtTTy InitBanner, Banner_strlen, 0 ; Display opening banner
; ------------------------------------------------------------------------
; Parse the command-line arguments, if any.
; ------------------------------------------------------------------------
call parse_args ; Parse options in CONFIG.SYS
cmp ax, INT_PASSED
jne init_error
; ------------------------------------------------------------------------
; Get a pointer to the BIOS data area to write the values.
; ------------------------------------------------------------------------
mov ax, 0 ; BIOS data area 0040:0000
mov bx, 0400h
mov cx, 4 ; four bytes long
mov dh, 1 ; get read/write data selector
@DevHlp PhysToUVirt
jc init_error
; ========================================================================
; Set the COM ownership words in the BIOS data area.
; ========================================================================
mov ax, com1
mov WORD PTR es:[bx+0], ax ; Set com1
mov ax, com2
mov WORD PTR es:[bx+2], ax ; Set com2
; ------------------------------------------------------------------------
; Release the selector to the BIOS data area.
; ------------------------------------------------------------------------
mov ax, es ; selector to free
mov dh, 2 ; release selector
@DevHlp PhysToUVirt
; ------------------------------------------------------------------------
; Set the ending offsets to unload initialization code and data.
; ------------------------------------------------------------------------
pop bx
pop es
lea ax, END_OF_CODE ; Place end of code segment into
mov WORD PTR Packet.InitpEnd, ax ; request packet
lea ax, END_OF_DATA ; Place end of data segment into
mov WORD PTR Packet.InitpEnd+2, ax ; request packet
jmp init_done
init_error:
pop bx ; restore ptr to request packet
pop es
mov fbError, 1
mov WORD PTR Packet.InitpEnd, 0
mov WORD PTR Packet.InitpEnd+2, 0
init_done:
ret
INIT ENDP
SUBTTL Parse command line arguments
PAGE +
; ***********************************************************************
; * CONFIG.SYS COMMAMD LINE PARSING *
; * *
; * The "command line" in CONFIG.SYS can be parsed by obtaining a read- *
; * only pointer to the start of the line after the DEVICE= string. *
; * The function parse_args returns INT_ERROR if there was an error on *
; * the command line, and INIT takes this to mean that the driver *
; * should not be loaded. INT_PASSED is returned on success. *
; * *
; * Example: *
; * DEVICE=\DEV\SETCOM40.SYS /COM1=3F8 /COM2=2F8 *
; ***********************************************************************
parse_args PROC NEAR
push es
push di
; Register usage:
; DS:SI -- source string pointer
; ES:DI -- destination string pointer (preserved)
; AX -- holds '/' and ES temporarily
; BX -- holds DI temporarily
; CX -- string comparison lengths
; DX -- remaining command line to process
les di, ArgPtr ; point after '='
;
; DEVICE=\DEV\SETCOM40.SYS /COM1=3F8 /COM2=2F8
; ^---this is pointed to by ES:DI now
;
push di ; Save DI index.
cld ; Process strings forward.
mov al, 0 ; ASCII 00h, 0Dh or 0Ah will terminate line.
mov cx, 80 ; Search no more than 80 characters (arbitrary)
repne scasb ; Scan, leaving DI pointing after it.
mov dx, di ; Points to char after EOL.
dec dx ; Point it TO the EOL.
pop di ; Restore DI index.
arg_loop:
cmp di, dx ; See if over end of line.
jl ok_to_check ; Not over edge, continue.
jmp arg_ok ; Must be finished.
ok_to_check:
mov cx, dx
sub cx, di ; Length of line in CONFIG.SYS
mov al, '/' ; Search for a '/' after driver name.
repne scasb ; Scan.
cmp cx, 0 ; See if there really WAS a '/'.
jg found_slash ; Yes, continue processing.
jmp arg_ok ; No, must be done.
found_slash:
;
; /COM1=hhh
;
mov bx, di ; Save starting address to compare.
mov si, OFFSET com1_string ; See if option is 'COM1='.
mov cx, com1_strlen ; Load string length.
repe cmpsb ; Compare.
jcxz is_com1 ; Jump if string matched 'COM1='.
jmp @F
is_com1:
mov bh, 3 ; Get the three hex digits of the
call htoi ; I/O port address.
cmp ax, INT_ERROR ; See if error occurred.
je bad_com1 ; If so, uh oh.
mov com1, ax ; Save it.
jmp arg_loop ; Get more options, if any.
bad_com1:
@SayBad com1_string, com1_strlen
mov ax, INT_ERROR ; Return error code.
jmp arg_done ; Get the hello out.
@@:
;
; /COM2=hhh
;
mov di, bx ; No, restore index.
mov si, OFFSET com2_string ; See if the option is 'COM2='.
mov cx, com2_strlen ; Load string length.
repe cmpsb ; Compare.
jcxz is_com2 ; Jump if string matched 'COM2='.
jmp @F
is_com2:
mov bh, 3 ; Get the three hex digits of the
call htoi ; I/O port address.
cmp ax, INT_ERROR ; See if error occurred.
je bad_com2 ; If so, uh oh.
mov com2, ax ; Save it.
jmp arg_loop ; Get more options, if any.
bad_com2:
@SayBad com2_string, com2_strlen
mov ax, INT_ERROR ; Return error code.
jmp arg_done ; Get the hello out.
@@:
@VioWrtTTy invparam_string, invparam_strlen, 0
mov ax, INT_ERROR ; Not a valid option.
jmp arg_done ; pop and exit.
arg_ok:
mov ax, INT_PASSED ; success
arg_done:
pop di
pop es
ret
parse_args endp
SUBTTL ASCII to binary conversion routines
PAGE +
;
; htoi converts a word represented in hexadecimal into binary.
;
htoi proc near
; PASSED:
; BH is number of digits (must be >= 1 and <= 4, not checked.)
; ES:[DI] points to string.
; RETURNED:
; AX returns word value.
; ES:[DI] ends up pointing one char AFTER last one converted.
; MODIFIED:
; CL holds digit temporarily during comparisons.
xor ax, ax ; Zero out AX register.
next_hdigit:
mov cl, BYTE PTR es:[di] ; Load digit into CL.
cmp cl, '0' ; See if it's >= '0'.
jge test_h9 ; Why yes, it is.
jmp bad_hdigit ; It isn't, can't be any digit.
test_h9:
cmp cl, '9' ; See if it's <= '9'.
jle is_hdecimal ; It's a normal decimal digit.
cmp cl, 'A' ; Is it a hexadecimal digit?
jge test_F ; Could be...see if it's <= 'F'.
jmp bad_hdigit ; Nope, you blew it; it's < 'A'.
test_F: cmp cl, 'F' ; Is it <= 'F'.
jg bad_hdigit ; Too big; you blew it.
sub cl, 'A'-10 ; Convert from ASCII hex to a number.
shl ax, 4 ; Shift over old digits.
and cx, 00FFh ; Make sure upper byte not OR'd in.
or ax, cx ; Add it in.
jmp test_hnext ; See if more digits to do.
is_hdecimal:
sub cl, '0' ; Convert from digit to a number.
shl ax, 4 ; Move over old digit(s).
and cx, 00FFh ; Make sure upper byte not OR'd in.
or ax, cx ; Add it in.
test_hnext:
inc di ; Move to next digit.
dec bh ; Decrement counter.
jnz next_hdigit ; If any left, go back to top.
jmp htoi_done ; Otherwise, blow this popsicle stand.
bad_hdigit:
mov ax, INT_ERROR
htoi_done:
ret
htoi endp
CODE ENDS
END