home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
ddkx86v5.zip
/
DDKX86
/
SRC
/
DEV
/
ATCOM
/
ATEISAI.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-04-14
|
33KB
|
780 lines
;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT Copyright (C) 1995 IBM Corporation
;
; The following IBM OS/2 WARP source code is provided to you solely for
; the purpose of assisting you in your development of OS/2 WARP device
; drivers. You may use this code in accordance with the IBM License
; Agreement provided in the IBM Device Driver Source Kit for OS/2. This
; Copyright statement may not be removed.;
;*****************************************************************************/
; SCCSID = @(#)ateisai.asm 6.3 91/04/22
; ***************************************************************************
; *
; *
; *
; ***************************************************************************
PAGE ,132
.286c
TITLE com01.sys - Asynchronous Communication Device Driver
NAME com01
;*** ateisai.asm - Parse EISA configuration for COM port
; information. This information will be used
; to intitialize the driver's data structures.
;
; EisaInit - Entry point for EISA init. code
;
; Modification History
;
; ACW 04/16/91 @PVW Added perfview counters/timers
;
; WDM 04/21/94 82548 - pvwxport.inc now included in atcom.inc
;
.xlist
; 82548 include pvwxport.inc ;@PVW
include basemaca.inc ; various macro's (break, ljc, etc.)
include devsym.inc
include devhlp.inc ; definition of device help calls.
include infoseg.inc ; structures defining the infoseg.
include filemode.inc ; file system file mode equates.
include struc.inc ; structured macros
.list
include atcom.inc
include ateisa.inc ; equates for eisa COM code
include eisa.inc
EXTRN DOSDEVIOCTL:far
EXTRN DOSOPEN:far
HSEG SEGMENT
PUBLIC IsEISA
PUBLIC SystemCOMs
oemhlp_name db "OEMHLP$ ",0 ; OEMHLP$ name
dev_str db "COM" ; device id
LEN_DEV_STR equ $-dev_str ; string length
type_str db "ASY" ; device type
LEN_TYP_STR equ $-type_str ; string length
sub_str db "COM" ; device subtype
LEN_SUB_STR equ $-sub_str ; string length
semi_str db ";" ; subtype delimiter
LEN_SEMI_STR equ $-semi_str ; string length
Slot EisaSlotInfo <> ; Slot info.
Function EisaFuncInfo <> ; Function info.
EisaCall EisaCallParameters <> ; EISA call info.
COMsFound db LEN_EISACOM_STRUC * MAXECOMPORTS DUP (0) ; array for EISA info.
SystemCOMs db LEN_EISACOM_STRUC * MAXECOMPORTS DUP (0) ; array for all system COM ports
com_index db 0 ; offset in to COMsFound array
bios_found dw MAXISACOMPORTS DUP (0) ; match found in EISA config. info
Temp_COMFound EISACom <> ; temp variable for sorting
IsEISA db 0 ; flag indicating valid EISA info.
oemhlp_handle dw 0 ; handle for file access
action dw 0 ; DOSOPEN parameter
HSEG ENDS
FA_SYSTEM equ 4 ; system file attribute
OEMHLP_CAT equ 80h ; DOSDEVIOCTL category
OPN_EXIST equ 0001h ; open an existing file/create a file
OPN_RDWRACC equ 0042h ; read/write access
RSEG SEGMENT PUBLIC 'RESCODE'
ASSUME CS:RSEG,DS:HSEG,ES:NOTHING,SS:NOTHING
;** EisaInit - entry point for EISA init. processing.
;
; This subroutine will get called from ComInit to check
; for the presence of an EISA system. If
; running on an EISA system, then this routine will
; parse the EISA system's non-volatile configuration CMOS,
; looking for COM port information. This information will be
; stored in a table, for use during ComInit's set-up of the 'ComN'
; data structures.
;
; ENTRY None
;
; EXIT IsEISA flag = 1 if EISA COM ports found
; = 0 otherwise
;
; USES flags, all other regs. restored
PUBLIC EisaInit
Procedure EisaInit
ASSUME CS:RSEG,DS:HSEG,ES:NOTHING,SS:NOTHING
pusha ; save all regs.
push es ; and ES, too
call OpenOEMHLP ; get access to OEMHLP$ driver,
.if < c > ; error?
jmp exit_eisai ; Y: exit
.endif
mov cl, 0 ; first slot #
push ds ; set ES to our DGROUP
pop es
slot_loop:
call GetSlotInfo ; get info. for first slot
.if < ah ne 0 > ; error?
.if < ah e EISA_ERROR_EMPTY_SLOT > ; empty slot?
inc cl ; Y: go to next slot number,
jmp slot_loop ; and process next slot
.elseif < ah e EISA_INVALID_SLOT > ; invalid slot?
jmp reconcile ; Y: reconcile info. found
.else ; not invalid or empty, so error exit
jmp exit_eisai ; then exit
.endif
.else ; Valid slot, check for I/O ports
.if < bit Slot.esi_fbFunc and EISA_HAS_IO_ENTRIES > I/O ports on this slot?
mov ch, Slot.esi_cbFunc ; Y: get number of functions
dec ch ; make it relative to 0
function_loop:
call GetFuncInfo ; get 320 byte record for this func.
.if < ah ne 0 > ; Error?
stc ; Y: indicate error, then
jmp exit_eisai ; error exit
.endif
lea si, Function.efi_achType ; point to device string
lea di, dev_str ; device string to look for
mov ax, LEN_DEV_STR ; string length
call strncmp ; is this function a COM device?
.if < z > and ; Y: also check to see if it's enabled
.if < bit Function.efi_fbFunction z EISA_FUNC_ENABLED > ; if enabled
lea si, Function.efi_achType ; point to dev. string
add si, LEN_DEV_STR ; point to the comma
inc si ; point to the type string
lea di, type_str ; type string to look for
mov ax, LEN_TYP_STR ; string length
call strncmp ; is this an asynchronous port?
.if < z >
call RecordFunc ; Y: store the information
.endif
.endif
.if < com_index e MAXECOMPORTS > ; Just found eighth COM port?
jmp reconcile ; Y: no need to search further
.endif
dec ch ; next function to check
.if < ch ge 0 > ; More functions to check?
jmp function_loop ; Y: check next function
.endif
.endif ; I/O ports
.endif ; No error on slot call
inc cl ; next slot to check
jmp slot_loop ; check next slot
reconcile:
.if < com_index g 0 > ; if any COM info. found, then
call CompareBIOS ; compare results to BIOS data area
call AddEISA ; then add in any EISA only COM ports
mov IsEISA, 1 ; indicate valid data
.endif
exit_eisai:
pop es ; restore regs.
popa
ret
EndProc EisaInit
;** AddEISA - Add in EISA COM ports.
;
; This routine fills in the data structure used to init. the driver
; with any information that was found on non-ISA compatible
; COM ports. These are COM ports that do not begin
; at the ISA compatible port addresses.
;
; ENTRY None.
;
; EXIT None.
;
; USES All registers destroyed.
;
public AddEISA
AddEISA proc near
.if < com_index e 0 > ; already matched up all the
ret ; EISA COM ports, so just exit
.endif
.if < com_index g 1 > ; if more than one un-matched
; EISA COM port remaining
; bubble sort the EISA COM ports
bubble_sort:
xor dx, dx ; assume sort is finished
mov cx, MAXECOMPORTS ; number of array items
dec cx ; adjust to loop count
mov si, OFFSET COMsFound ; start of EISA array
scan_array:
mov al, [si].COMport_number ; unit number
mov di, si
add di, LEN_EISACOM_STRUC ; point to next entry
.if < al g [di].COMport_number > ; if these aren't in order
mov dx, 1 ; not through sorting yet
push si ; save current offset
push cx ; save loop count
push di ; save current+1 offset
push si ; save current offset
mov di, OFFSET Temp_COMFound ; temp buffer
mov cx, LEN_EISACOM_STRUC / 2 ; prepare for word move
rep movsw ; copy current array entry to temp.
pop di ; get current offset back
pop si ; get current+1 offset back
push si ; save current+1 offset
mov cx, LEN_EISACOM_STRUC / 2 ; prepare for word move
rep movsw ; copy current+1 to current
pop di ; get current+1 offset back
mov si, OFFSET Temp_COMFound ; temp buffer
mov cx, LEN_EISACOM_STRUC / 2 ; prepare for word move
rep movsw ; copy from tmp to current+1
pop cx ; get loop count back
pop si ; get current offset back
.endif
add si, LEN_EISACOM_STRUC ; point to next array element
loop scan_array ; check next two items
.if < dx e 1 > ; is the array sorted yet?
jmp bubble_sort ; N: try again
.endif
.endif
; Now scan the sorted array, looking for un-used EISA COM ports.
mov al, MAXISACOMPORTS ; offset to first available EISA slot
xor ah, ah
mov bx, LEN_EISACOM_STRUC
mul bx ; construct an offset in to the
; driver's data structure
mov di, OFFSET SystemCOMs ; beginning of driver's data structure
add di, ax ; first empty entry in driver's data
mov cx, MAXECOMPORTS ; max. number of EISA COM ports
mov si, OFFSET COMsFound ; first entry in EISA array
mov dl, MAXISACOMPORTS ; to keep track of total
mov bl, dl ; use as an index into int. routines
xor bh, bh
shl bx, 1 ; X 2 to create an offset
scan_eisa:
.if < [si].COMport_number g 0 > and ; if valid data
.if < [si].In_use e 0 > and ; and this COM port is not in use
.if < [si].base_addr ne COM1_PORT > and ; and it's not ISA COM1
.if < [si].base_addr ne COM2_PORT > ; or ISA COM2
; fill in the device driver's data structure with the
; EISA config. information
mov ax, [si].base_addr ; get base addr from EISA
mov [di].base_addr, ax ; have the driver use it
mov al, [si].IRQ_number ; get IRQ level from EISA
mov [di].IRQ_number, al ; have the driver use it
mov al, [si].sharable_IRQ ; get IRQ sharing info. from EISA
mov [di].sharable_IRQ, al ; have the driver use it
add di, LEN_EISACOM_STRUC ; point to next free entry
inc bx
inc bx ; point to next int. routine
inc dl ; add another COM port
.if < dl e MAXECOMPORTS > ; max reached?
jmp exit_add ; Y: exit
.endif
.endif
add si, LEN_EISACOM_STRUC ; point to next EISA COM port
loop scan_eisa ; process all EISA COM ports
exit_add:
ret
AddEISA endp
;** atoi
;
; Converts the string at DS:SI in to an integer value. Does
; not assume NULL termination - searches for the first
; non-ASCII digit instead.
;
; ENTRY (ds:si) -> String to convert
;
; EXIT if 'C' clear
; AX = integer value
; else
; invalid input
;
; USES Flags, all other registers restored.
;
public atoi
atoi proc near
push si ; save regs.
push bx
push cx
push dx
xor ah, ah ; clear high order byte
mov bx, 1 ; initial power of ten multiplier
xor cx, cx ; initial string size
xor dx, dx ; eventual result
cld ; go forward to find the end
find_end_digits:
lodsb ; get a char
.if < al ge '0' > and ; if in range
.if < al le '9' > ; then
inc cx ; increment string size
jmp find_end_digits ; and keep looking
.endif
.if < cx e 0 > ; no digits found?
stc ; indicate error
jmp exit_atoi ; then exit
.endif
dec si ; back up to non-digit char.
dec si ; back up to least significant digit
std ; go backwards from least to most sig.
convert:
lodsb ; get a digit
sub al, '0' ; strip off the ASCII portion
push dx ; save the work in progress
mul bx ; calculate this position
pop dx ; retrieve work done so far
add dx, ax ; accumulate this new position
.if < bx e 1 > ; special case for first time
mov bx, 10 ; initial powers of ten value
.else
mov ax, 10 ; to create next power of ten
push dx ; save work in progress
mul bx ; create next power of ten
pop dx ; restore work in progress
mov bx, ax ; put back in powers of 10 reg.
.endif
loop convert ; loop until all are converted
mov ax, dx ; move result to return value
clc ; indicate no error
exit_atoi:
pop dx ; restore regs
pop cx
pop bx
pop si
ret
atoi endp
;** CompareBIOS
;
; This function reconciles the data found in the EISA
; config. information with the BIOS data area's COM
; base address array. The purpose of this routine is to
; ensure ISA/DOS compatibility. By looking at the BIOS
; data area first, we can handle the possiblity of an ISA
; card being plugged in to an EISA machine without a
; corresponding EISA config. file.
;
; To accomplish this, two things are done. First, the EISA
; config. information is compared to the BIOS data area.
; For each match between the two, an entry is initialized
; in the data structure that is used to initialize the driver.
; After this is done, the result is checked against the
; BIOS data area. If there are any BIOS data area entries
; that do not have a corresponding entry in the data structure used to
; initialize the driver, then the driver data structure is filled
; in with ISA defaults.
;
; ENTRY None
;
; EXIT None
;
; USES All registers destroyed.
;
public CompareBIOS
CompareBIOS proc near
push es ; save our data selector
mov ax, COM_SEG ; get selector for BIOS data area
mov es, ax
xor bx, bx ; create offset to BIOS data area
mov cl, com_index ; number of COM ports in EISA info.
xor ch, ch ; clear high byte
mov di, OFFSET COMsFound ; beginning of EISA array
check_all_EISA_COMs:
push cx ; save # of EISA COM ports loop count
mov cl, MAXISACOMPORTS ; max. number of BIOS found COM ports
; supported
xor dx, dx ; array index
push bx ; save beginning index
check_all_BIOS_entries:
mov ax, [di].base_addr ; EISA base addr.
.if < <word ptr es:[bx]> g 0 > and ; if there is a BIOS data entry
.if < es:[bx] ge ax > ; and it could be in range
mov ax, [di].end_addr ; get the end of the range
.if < es:[bx] le ax > and ; if in range
.if < [di].In_use e 0 > ; and this EISA info. hasn't been used
mov [di].In_use, 1 ; a match has been found, mark this
; entry as being in use.
push dx ; save array index
push bx ; save offset to BIOS data area
mov ax, dx ; get array index
mov bx, LEN_EISACOM_STRUC
mul bx ; create an offset
mov bx, ax ; set up an index
; fill in the device driver's data structure with the
; EISA config. information
mov ax, [di].base_addr ; get base addr from EISA
mov SystemCOMs[bx].base_addr, ax ; save for use by the driver
mov al, [di].IRQ_number ; get IRQ level from EISA
mov SystemCOMs[bx].IRQ_number, al ; save for use by the driver
mov al, [di].sharable_IRQ ; get IRQ sharing info. from EISA
mov SystemCOMs[bx].sharable_IRQ, al ; save for use by the driver
pop bx ; restore offset to BIOS data area
pop dx ; restore array index
push bx ; save offset to BIOS data area
mov bx, dx ; get the array index
shl bx, 1 ; adjust to word offset
mov bios_found[bx], 1 ; indicate valid info.
pop bx ; restore offset to BIOS data area
dec com_index ; keep track of how many EISA LPTs used
.endif
.endif
inc bx
inc bx ; point to the next BIOS data entry
inc dx ; next array index
loop check_all_BIOS_entries ; process each valid BIOS entry
pop bx ; restore initial offset to BIOS
pop cx ; restore EISA loop count
add di, LEN_EISACOM_STRUC ; point to next array entry
loop check_all_EISA_COMs ; process all EISA COM ports found
mov cx, MAXISACOMPORTS ; loop counter
xor bx, bx ; offset into BIOS data area
mov di, OFFSET SystemCOMs ; "save" array
fill_in_ISA_values:
.if < <word ptr es:[bx]> ne 0 > and ; if there is a COM port
.if < bios_found[bx] e 0 > ; and no EISA info. was found
; Fill in the total system COM port array with ISA defaults,
; since no EISA config. information was found.
mov [di].sharable_IRQ, 0 ; no IRQ sharing
mov ax, es:[bx] ; port addr.
mov [di].base_addr, ax ; have device driver use it
.if < ax e COM1_PORT > ; COM1 base address?
mov [di].IRQ_number, COM1_VEC ; use IRQ4
.else ; use IRQ3
mov [di].IRQ_number, COM2_VEC
.endif
.endif
inc bx
inc bx ; next BIOS data area entry
add di, LEN_EISACOM_STRUC ; next detice driver entry
loop fill_in_ISA_values ; process all BIOS data area COM ports
pop es ; get our data selector back
ret
CompareBIOS endp
;** GetFuncInfo
;
; Set up an IOCTL structure to call OEMHLP for EISA
; function information.
;
; ENTRY <cl> = Slot number requested
; <ch> = Function number requested
;
; EXIT if <ah> = 0
; Variable 'Function' contains result
; else
; <ah> contains error code
;
; USES ax
;
public GetFuncInfo
GetFuncInfo proc near
mov EisaCall.ecp_SubFunction, EISA_FUNCTION_REQUEST ; tell OEMHLP$ "get function info."
mov EisaCall.ecp_SlotNumber, cl ; requested slot number
mov EisaCall.ecp_FunctionNumber, ch ; requested function number
push ds
push OFFSET Function ; returned data structure
push ds
push OFFSET EisaCall ; parm. list
push EISA_FNNUMBER ; request code for EISA BIOS call
push OEMHLP_CAT ; IOCTL category code
push [oemhlp_handle] ; file handle
call DOSDEVIOCTL ; make call to OEMHLP$
.if < ax ne 0 > ; error?
mov ah, EISA_INVALID_BIOS_CALL ; Y: Indicate not EISA machine
.else
mov ah, Function.efi_bReturn ; N: Use the EISA return code
.endif
ret
GetFuncInfo endp
;** GetSlotInfo
;
; Set up an IOCTL structure to call OEMHLP for EISA
; slot information.
;
; ENTRY <cl> = Slot number requested
;
; EXIT if <ah> = 0
; Variable 'Slot' contains result
; else
; <ah> contains error code
;
; USES ax
;
public GetSlotInfo
GetSlotInfo proc near
mov EisaCall.ecp_SubFunction, EISA_SLOT_REQUEST ; tell OEMHLP$ "get slot info."
mov EisaCall.ecp_SlotNumber, cl ; requested slot number
push ds
push OFFSET Slot ; returned data structure
push ds
push OFFSET EisaCall ; parm. list
push EISA_FNNUMBER ; request code for EISA BIOS call
push OEMHLP_CAT ; IOCTL category code
push [oemhlp_handle] ; file handle
call DOSDEVIOCTL ; make call to OEMHLP$
.if < ax ne 0 > ; error?
mov ah, EISA_INVALID_BIOS_CALL ; Y: Indicate not EISA machine
.else
mov ah, Slot.esi_bReturn ; N: Use the EISA return code
.endif
ret
GetSlotInfo endp
;** OpenOEMHLP
;
; Uses DOSOPEN to get a handle for access to OEMHLP$
;
; ENTRY None
;
; EXIT if 'C' clear
; OEMHLP_handle set
; else
; error
;
; USES AX
;
public OpenOEMHLP
OpenOEMHLP proc near
push ds
push OFFSET oemhlp_name ; device name
push ds
push OFFSET oemhlp_handle ; file handle
push ds
push OFFSET action ; action taken
push 0 ; high order half of file size
push 0 ; low order half of file size
push FA_SYSTEM ; file attribute
push OPN_EXIST ; fail if it does not exist
push OPN_RDWRACC ; get read/write access
push 0 ; reserved
push 0 ; reserved
call DOSOPEN ; get a handle for OEMHLP$
.if < ax e 0 > ; error?
clc ; N: indicate no error
.else
stc ; Y: indicate error
.endif
ret
OpenOEMHLP endp
;** RecordFunc
;
; After a function has been found that is an asynchronous COM device,
; this routine is called to save the configuration
; of the device.
;
; ENTRY Function - contains information on a COM device
;
; EXIT COMs - updated
;
; USES All registers restored.
;
public RecordFunc
RecordFunc proc near
pusha ; save regs.
lea si, Function.efi_achType ; device type string
mov di, OFFSET semi_str ; delimiter string to look for
mov bx, LEN_SEMI_STR ; length of delimiter string
mov ax, EISA_DEVICE_TYPE_LEN ; size of type ASCII string field
call ScanString ; is there a subtype delimiter?
.if < nz > ; N: return to caller
jmp record_exit
.endif
mov di, OFFSET sub_str ; beginning of subtype string
mov bx, LEN_SUB_STR ; length of subtye string
inc si ; first char. after subtype delim.
mov ax, OFFSET Function ; beginning of structure
add ax, OFFSET efi_achType ; adjusted to beginning of ASCII
add ax, EISA_DEVICE_TYPE_LEN ; add max. offset
sub ax, si ; subtract current offset for len.
call ScanString ; is the subtype string 'COM'?
.if < nz > ; N: return to caller
jmp record_exit
.endif
dec si ; check to make sure 'COM' is alone:
cld ; make sure we're going forward
lodsb ; get char. right before 'COM'
.if < al e ';' > or ; semicolon?
.if < al e ' ' > or ; or a space?
.if < al e TAB > ; or a TAB?
nop ; Y: then it's OK, keep going
.else
jmp record_exit ; N: something in front of 'COM', exit
.endif
add si, LEN_SUB_STR ; point to unit number
call atoi ; attempt to convert to integer
.if < c > ; valid integer?
jmp record_exit ; N: so exit
.endif
push ax ; save the integer value
mov ax, LEN_EISACOM_STRUC ; struc. size
mul com_index ; multiplied by current index
mov bx, ax ; yields an offset.
inc com_index ; increment for next time
pop ax ; get integer back
mov COMsFound[bx].COMport_number, al ; store the unit number
lea si, Function.efi_eiri
lodsb ; get IRQ info.
.if < bit al and EISA_IRQ_SHARABLE > and ; is the IRQ sharable?
.if < bit al and EISA_IRQ_LEVEL > ; AND level triggered?
mov COMsFound[bx].sharable_IRQ, INT_SHARING ; it is sharable
.else
mov COMsFound[bx].sharable_IRQ, 0 ; not sharable
.endif
and al, 0Fh ; mask off all but IRQ number
mov COMsFound[bx].IRQ_number, al ; store IRQ number
lea si, Function.efi_epi ; port info.
cld ; go forward
lodsb ; get I/O port information
and al, EISA_NUMBER_PORTS ; mask off all but number of ports
mov cx, ax ; save the number of ports
lodsw ; get base port addr
mov COMsFound[bx].base_addr, ax ; store base addr
add ax, cx ; calculate last port addr
mov COMsFound[bx].end_addr, ax ; store end addr
record_exit:
popa ; restore regs.
ret
RecordFunc endp
;** ScanString
;
; Searches the string at DS:SI for an occurrence of the string
; at ES:DI. Updates DS:SI.
;
; ENTRY <ax> = length of string to be scanned
; <bx> = pattern length
; <ds:si> - String to search
; <es:di> - Pattern to match
;
; EXIT if 'Z' = 1
; search pattern was found, <si> -> offset
; else
; search pattern not found
;
; USES SI
;
public ScanString
ScanString proc near
push cx ; save count register
mov cx, ax ; get the string length
mov ax, bx ; get the pattern length
dec si ; pre-decrement for loop
search_string:
inc si ; point to next attempt
call strncmp ; compare the strings
loopnz search_string ; keep trying
pop cx ; restore the count register
ret ; and exit
ScanString endp
;** strncmp
;
; Compares two strings for a given length; ignores null
;
; ENTRY <ax> = string length
; <ds:si> - string 1
; <es:di> - string 2
;
; EXIT if 'Z' = 1
; the strings did compare
; else
; the strings did not compare
;
; USES All registers restored
;
strncmp proc near
push cx ; save regs.
push si
push di
mov cx, ax ; get the string length
cld ; go forward
repe cmpsb ; compare the strings
pop di ; restore regs.
pop si
pop cx
ret ; and exit
strncmp endp
RSEG ENDS
END