home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
ddkx86v5.zip
/
DDKX86
/
SRC
/
PEN
/
PENTKT
/
PENBASE
/
SERIAL.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-04-14
|
14KB
|
521 lines
;*DDK*************************************************************************/
;
; 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.;
;*****************************************************************************/
; /*****************************************************************/
; /* */
; /* */
; /*****************************************************************/
; /******************* START OF SPECIFICATIONS *********************/
; /* */
; /* SOURCE FILE NAME: SERIAL.ASM */
; /* */
; /* DESCRIPTIVE NAME: Serial IO routine */
; /* */
; /* */
; /* STATUS: Version 1.0 */
; /* */
; /* NOTES: This module contains routines to manage a COM port. */
; /* */
; /* ENTRY POINTS: */
; /* See public statements */
; /* EXTERNAL REFERENCES: */
; /* See extrn statements */
; /* */
; /******************* END OF SPECIFICATIONS *********************/
.xlist
include pensegs.inc
include pen.inc
include serial.inc
include devhlp.inc
include struc.inc
.list
;------- ABIOS ERRORs --------------------
MSG_MEMORY_ALLOCATION_FAILED EQU 0
ERROR_LID_ALREADY_OWNED EQU 1
ERROR_LID_DOES_NOT_EXIST EQU 2
ERROR_ABIOS_NOT_PRESENT EQU 3
ERROR_NOT_YOUR_LID EQU 4
ERROR_INVALID_ENTRY_POINT EQU 5
;------- LOCAL EQUATES -------------------
INTERRUPT_TEST EQU 1000b
INTERRUPT_INIT_MASK EQU 07h
.286p
;------------------------------------------------------------------------------
;declare external variables
;------------------------------------------------------------------------------
extrn Device_Help : dword
extrn Dev_ErrorCount : dword
;------------------------------------------------------------------------------
;declare external routines
;------------------------------------------------------------------------------
extrn Trc_INT : near
extrn Trc_DD : near
CSEG SEGMENT
ASSUME CS:CGROUP, SS:nothing, ES:nothing, DS:DGROUP
;---- SERVICE ROUTINES --------------------------------------------------------
;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Change the baud rate
; bx = dcb
; si = serial struc
; al = baud rate
;------------------------------------------------------------------------------
public Ser_ChangeBaud
Ser_ChangeBaud proc near
; disable interrupts for the device at the PIC
push ax
call Ser_DisableInts
pop ax
mov [si].comdivisor, al
; Reset DLAB in order to set baud rate
mov ah, LCR
mov al, 80H
call Ser_DoOut
; Set Baud
sub al, al
mov ah, LATMSB
call Ser_DoOut
mov al, [si].comdivisor
mov ah, LATLSB
call Ser_DoOut
; Reset DLAB, set LCR
mov ah, LCR
mov al, [si].comLCR
call Ser_DoOut
; Enable device at the PIC
call Ser_EnableInts
ret
Ser_ChangeBaud endp
;------------------------------------------------------------------------------
; set state of FIFO
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public Ser_FIFO
Ser_FIFO Proc Near
.if <[si].fcomFIFO ne 0>
mov ah, FCR
mov al, [si].comFCR
call Ser_DoOut
.endif
ret
Ser_FIFO endp
;------------------------------------------------------------------------------
; resume interrupt driven events
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public Ser_EnableInts
Ser_EnableInts Proc Near
pushf ; save state of IF
DISABLE ; Hold interrupts for 8259 Update
; begin defect 69804
; if interrupt level is < 8 process the master PIC
test [si].interruptLevel, INTERRUPT_TEST
jz enable_master
; process slave PIC
in al, 0A1h
and al, [si].enable_8259
out 0A1h, al
popf
ret
; process master PIC
enable_master:
; end defect 69804
in al, 21h ; Get current Interrupt Mask
and al, [si].enable_8259 ; Set serial Interrupt IRQ Bit - OFF
out 21h, al ; set innterrupt mask
popf ; restore interrupt flag state
ret
Ser_EnableInts EndP
;------------------------------------------------------------------------------
; suspend interrupt driven events
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public Ser_DisableInts
Ser_DisableInts Proc Near
pushf ; save state of IF
DISABLE ; Hold interrupts for 8259 Update
; begin defect 69804
; if interrupt level is < 8 process the master PIC
test [si].interruptLevel, INTERRUPT_TEST
jz disable_master
; process slave PIC
in al, 0A1h
or al, [si].disable_8259
out 0A1h, al
popf
ret
; process master PIC
disable_master:
; end defect 69804
in al, 21h ; Get current Interrupt Mask
or al, [si].disable_8259 ; Set Mouse Interrupt IRQ Bit - ON
out 21h, al ; Reset 8259 holding Mouse ints
popf ; restore interrupt flag
ret
Ser_DisableInts EndP
;------------------------------------------------------------------------------
; output a byte
; ah = register offset from base
; al = byte to write
; si = serial struc
;------------------------------------------------------------------------------
public Ser_DoOut
Ser_DoOut proc
mov dx, [si].port
add dl, ah
out dx, al
;MyIODelay
ret
Ser_DoOut endp
;------------------------------------------------------------------------------
; write a byte, check that port is ready for it
; al = byte to write
; si = serial struc
;------------------------------------------------------------------------------
public Ser_DoPut
Ser_DoPut proc
push ax
.repeat
mov ah,LSR
call Ser_DoIn
test al, 020h
.until nz
pop ax
mov ah,TXB
call Ser_DoOut
ret
Ser_DoPut endp
;------------------------------------------------------------------------------
; get a byte
; ah = register offset from base
; si = serial struc
; returns
; al = byte from port
;------------------------------------------------------------------------------
public Ser_DoIn
Ser_DoIn proc
mov dx, [si].port
add dl, ah
in al, dx
;MyIODelay
ret
Ser_DoIn endp
;---- PROCESS BYTES -----------------------------------------------------------
;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; interrupt handler
; bx = dcb
; si = serial struc
;------------------------------------------------------------------------------
public Ser_InterruptHandler
Ser_InterruptHandler proc far
DISABLE
TraceInt
; issue the EOI and disable the IRQ
call Ser_DisableInts
; mov al, [si].interruptLevel
; mov dl, DevHlp_EOI
; call Device_Help
ENABLE
; process bytes
.repeat
call readByte ; returns al = interrupt data
push si
call [si].@processByte ; bx = dcb
pop si ; al = byte
mov dx, [si].port ; Setup Mouse Input Port Number
add dx, LSR ; Check Line Status Reg
in al, dx ; Read Line Status Data
.until <bit AL z 01H> near ; check for more data
call Ser_EnableInts ; make sure IRQ enabled
mov al, [si].interruptLevel
mov dl, DevHlp_EOI
call Device_Help
clc ; clear carry for our int
ret ; return to intr hndlr
Ser_InterruptHandler endp
;------------------------------------------------------------------------------
; read a byte for the serial port
; si = serial struc
;------------------------------------------------------------------------------
Public readByte
readByte Proc Near
DISABLE
MOV DX, [si].port ; Setup Mouse Input Port Number
IN AL, DX ; Read incoming Interrupt data Byte
PUSH AX ; Save Data Byte
ADD DX, LSR ; Check Line Status Reg
IN AL, DX ; Read Line Status Data
MOV cl, AL ; Get Error Code in cl
POP AX ; Restore Data Byte
.IF <bit cl nz LS_PERR+LS_FERR> ; If an Error occured then
.386p
inc Dev_ErrorCount
.286p
push bx
call [si].@errorRtn ; bx = dcb
call Ser_Error
pop bx
xor ax,ax ; this won't match sync bits
.ENDIF ; Data Error Tests
ENABLE
ret
readByte EndP
;---- INITIALIZATION ROUTINES -------------------------------------------------
; note: Must be in resident code incase of IO error
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Initialize the port.
; si = serial data
;------------------------------------------------------------------------------
public Ser_Init
Ser_Init Proc
; claim ASYNC port to keep COM.SYS's hands off
mov al, 06h ; Async Device ID
mov bl, [si].comPort ; Get the LID
xor dh, dh
mov dl, DevHlp_GetLIDEntry
call Device_Help
.if <c>
.if <ax ne ERROR_ABIOS_NOT_PRESENT>
PANIC PANIC_SERNOLID
.endif
.else
or [si].serialStatus,ABIOSLID
.endif
; Zero out BIOS data area for the Communications Line Port Base address.
; 40:0 for Com Port 1
; 40:2 for Com Port 2
; 40:4 for Com Port 3
; 40:6 for Com Port 4
push es
mov bl, [si].comPort
dec bl
xor bh, bh
shl bx, 1
push 40h
pop es
mov word ptr es:[bx], 0
pop es
; Build 8259 IC Mask from returned IRQ #
mov cl, [si].interruptLevel
; begin defect 69804
; map interrupt levels 8-15 to 0-7 for assigning disable_8259 and enable_8259
and cl, INTERRUPT_INIT_MASK
; end defect 69804
mov ax, 0001h
shl ax, cl
mov [si].disable_8259, al ; Save Disable 8259 Mask
not al ; Invert Mask for Enable Bits
mov [si].enable_8259, al ; Save Enable 8259 Mask
; check FIFO level
mov ah, FCR
mov al, FIFO_ENABLE
call Ser_DoOut
mov ah, IIR
call Ser_DoIn
.if < bit al nz FIFOMASK >
mov [si].fcomFIFO, FIFO_ENABLE
.else
mov [si].fcomFIFO, FIFO_DISABLE
.endif
; Disable FIFO
mov ah, FCR
mov al, 0
call Ser_DoOut
; Check to see if port exists.
mov ah, IIR
call Ser_DoIn
test al, IIRMASK ; Check reg permanent bits
.if <nz> ; if port does not exist
PANIC PANIC_SERNOPORT
.else
or [si].serialStatus,COMEXIST
.endif
; Now go claim the IRQ level.
push bx
mov ax, [si].@IntHandler ; offset of interrupt routine
xor bh, bh ; clear upper byte
mov bl, [si].interruptLevel ; get IRQ needed
xor dh, dh ; IRQ level as unshared
mov dl, DevHlp_SetIRQ ; function number
call Device_Help ; go do it
pop bx ; restore dcb
.if <c> ; if error
PANIC PANIC_SERNOIRQ ; (returns with cary set)
.else
or [si].serialStatus,SETIRQ_DONE
.endif
public Ser_Error
Ser_Error:
; Disable device from interrupting at the PIC
call Ser_DisableInts
; Disable interrupts at the device
mov ah, IER
xor al, al
call Ser_DoOut
; Reset DLAB in order to set baud rate
mov ah, LCR
mov al, 80H
call Ser_DoOut
; Set Baud
sub al, al
mov ah, LATMSB
call Ser_DoOut
mov al, [si].comdivisor
mov ah, LATLSB
call Ser_DoOut
; Reset DLAB, set LCR
mov ah, LCR
mov al, [si].comLCR
call Ser_DoOut
; Set Modem Control Reg
mov ah, MCR
mov al, [si].comMCR
call Ser_DoOut
; Read stray data
mov ah, RXB
mov cx, 0FFFFH
.repeat
call Ser_DoIn
.loop
; call back to device dependent routine to do its intialization
mov bx,[si].@DCB
CALL_NZ_OK [si].@InitRtn
; set FIFO
call Ser_FIFO
; Enable interrupts at device
mov ah, IER
mov al, IERMASK
call Ser_DoOut
; Enable device at the PIC
call Ser_EnableInts
ret
Ser_Init endp
CSEG ends
end