david@kessner.denver.co.us (David D. Kessner) (02/26/91)
Here are the serial drivers that you all requested! I think that there is
probably a different news group that this REALLY belongs to, but the source is
small and comp.os.msdos.programmer is where the original post was made...
There are two files, async.h and async.asm, included at the
end of this message. Just look for the '------' cut here markers.
ASYNC.H is containes all of the funtion prototypes needed to use the
assembly code from a C program, and ASYNC.ASM is the code itself. I have
used these with Turbo C, and Turbo ASM without any problems. It should work
with Microsoft C and ASM, but a bit of re-writing will be needed to make the
assmebler part work.
Here is a short tutorial of the Async functions:
AsyncInit( int Port)
AsyncStop( void)
These functions start and stop the interrupt handlers. No characters can be
recieved if it isn't started, and the computer will crash if they are not
stopped before the program is exited. The paramater 'port' is the COM port
to use, there are #defines in the header file that defines the values to be
used. It would be 'more bug proof' if AsyncStop was called via the atexit()
function (check your compiler manual).
AsyncClear( void)
Clears the internal buffers.
AsyncOut( int c)
Sends out a character.
AsyncIn( void)
Returns the next character in the buffer or a NULL upon an empty buffer. Use
AsyncInStat() to check for the number of characters in the buffer.
AsyncHand( int handshake)
Sets the status of the handshaking lines. The values are defined in the
header file and can be or'd together. A typical call would look like this:
AsyncHand( DTR | RTS);
AsyncSet( int Baud, int Control)
This sets the baud rate, paraty, etc, of the serial line. The paramater 'Baud'
is the baud rate (ie 1200, 2400, 9600, etc), and 'control' should be 3 for
8 bits, 1 stop bit, and no parity.
AsyncInStat( void)
This frunction returns the number of characters in the input buffer.
AsyncOutStat( void)
Returns the number of characters in the output buffer.
AsyncStat( void)
Returns the status of the handshaking lines. Use the & and | oporaters with
the values defined in the header file to extract any useful informaton out of
this value.
The values used include the normal DCD, RI, and CTS, but also include D_DCD for
'Delta-DCD' or CHANGE IN DCD. This is useful in detecting changes in the
handshaking lines since the last time the status was read.
These routines do have their limitations, however. They cannot deal with more
than one serial port, and cannot take advantage of the 16550 UART. There is
also no routines for input and output of strings-- there is so many ways of
doing it that I left it up to whoever used these routines.
Enjoy, and if you have any questions, dont hesitate to ask.
- David K
David Kessner - david@kessner.denver.co.us | do {
1135 Fairfax, Denver CO 80220 (303) 377-1801 (p.m.) | . . .
This is my system so I can say any damn thing I want! | } while( jones);
---------------------------- async.h ----------------------------------------
#ifndef _ASYNC_H_
#define _ASYNC_H_
void AsyncInit( int Port),
AsyncStop( void),
AsyncClear( void),
AsyncOut( int c),
AsyncHand( int handshake),
AsyncSet( int Baud, int Control);
int AsyncIn( void),
AsyncInStat( void),
AsyncOutStat( void);
unsigned AsyncStat( void);
#define COM1 0
#define COM2 1
#define COM3 2
#define COM4 3
/* Defines for AsyncHand() */
#define DTR 0x01
#define RTS 0x02
#define USER 0x04
#define LOOPBACK 0x10
/* Defines for AsyncStat() */
#define D_CTS 0x0100
#define D_DSR 0x0200
#define D_RI 0x0400
#define D_DCD 0x0800
#define CTS 0x1000
#define DSR 0x2000
#define RI 0x4000
#define DCD 0x8000
#define PARITY 0x0004
#define THREMPTY 0x0020
#define BREAKDET 0x1000
#endif
------------------------------ asnyc.asm -----------------------------------
; Async Module.
IDEAL
MODEL compact
EOI equ 020h ; 8259 end-of-interupt
Ctrl8259_0 equ 020h ; 8259 port
Ctrl8259_1 equ 021h ; 8259 port (Masks)
BufSize equ 1024 ; Buffer Size
DATASEG
; Various things to be set upon AsyncInit()
VectorNum db ? ; Vector Number
EnableIRQ db ? ; Mask to enable 8259 IRQ
DisableIRQ db ? ; Mask to disable 8259 IRQ
VectorSeg dw ? ; Old Vector Segment
VectorOfs dw ? ; Old Vector Offset
; Register Addresses for the 8250 UART
Port dw ? ; Port Base Address
LABEL RegStart word
THR dw ? ; Transmitter Holding Register
RDR dw ? ; Reciever Data Register
BRDL dw ? ; Baud Rate Divisor, Low byte
BRDH dw ? ; Baud Rate Divisor, High Byte
IER dw ? ; Interupt Enable Register
IIR dw ? ; Interupt Identification Register
LCR dw ? ; Line Control Register
MCR dw ? ; Modem Control Register
LSR dw ? ; Line Status Register
MSR dw ? ; Modem Status Register
; Buffer Data
RecBuffer db BufSize DUP (?) ; Recieve Buffer
RecHead dw ? ; Buffer Head Pointer
RecTail dw ? ; Buffer Tail Pointer
TransBuffer db BufSize DUP (?) ; Transmit Buffer
TransHead dw ? ; Buffer Head Pointer
TransTail dw ? ; Buffer Tail Pointer
; Register Offsets for the UART
RegOffsets dw 0, 0, 0, 1, 1, 2, 3, 4, 5, 6
CODESEG
PUBLIC _AsyncInit, _AsyncClear, _AsyncStop
PUBLIC _AsyncIn, _AsyncOut, _AsyncSet
PUBLIC _AsyncHand, _AsyncStat, _AsyncInStat
PUBLIC _AsyncOutStat
;-----------------------------------------------------------------------------
; AsyncClear Empty the recieve buffer
;-----------------------------------------------------------------------------
; void AsyncClear( void);
;
;
;-----------------------------------------------------------------------------
PROC _AsyncClear
cli
push ax
mov ax, offset RecBuffer
mov [RecHead], ax
mov [RecTail], ax
mov ax, offset TransBuffer
mov [TransHead], ax
mov [TransTail], ax
pop ax
sti
ret
ENDP _AsyncClear
;-----------------------------------------------------------------------------
; AsyncInit Initalize Serial Port and install ISR
;-----------------------------------------------------------------------------
; void AsyncInit( int port)
;
; Where Port is
; 0 = COM1
; 1 = COM2
; 2 = COM3
; 3 = COM4
;
;-----------------------------------------------------------------------------
PROC _AsyncInit
ARG CommPort:word
push bp
mov bp, sp
;---- Set various things according to com port number
mov ax, [CommPort]
;----- COM1
cmp ax, 0
jne @@1
mov [Port], 03F8h
mov [VectorNum], 0Ch
mov [EnableIRQ], 0EFh
mov [DisableIRQ], 10h
jmp @@Done
@@1:
;----- COM2
cmp ax, 1
jne @@2
mov [Port], 02F8h
mov [VectorNum], 0Bh
mov [EnableIRQ], 0F7h
mov [DisableIRQ], 08h
jmp @@Done
@@2:
;----- COM3
cmp ax, 2 ; 2
jne @@3
mov [Port], 03E8h ; 03E8
mov [VectorNum], 0Ch ; 0C
mov [EnableIRQ], 0EFh ; EF
mov [DisableIRQ], 10h ; 10
jmp @@Done
@@3:
;----- COM4
mov [Port], 02E8h ; 02E8
mov [VectorNum], 0Bh ; 0B
mov [EnableIRQ], 0F7h ; F7
mov [DisableIRQ], 08h ; 08
@@Done:
;---- Compute Register locations
mov cx, 10
mov bx, offset RegOffsets
push di
mov di, offset RegStart
@@4:
mov ax, [bx]
add ax, [Port]
mov [di], ax
add bx, 2
add di, 2
loop @@4
pop di
;----- Initalize Buffer
call _AsyncClear
;--- Save and reassign interrupt vector
push ds ; Save Old Vector
mov al,[VectorNum]
mov ah,35h
int 21h
mov [VectorSeg], es
mov [VectorOfs], bx
mov al, [VectorNum]
push cs ; Set New Vector
pop ds
mov dx, offset AsyncISR
mov ah, 25h
int 21h
pop ds
;----- Enable 8259 interrupt (IRQ) line for this async adapter
in al, Ctrl8259_1
and al, [EnableIRQ]
out Ctrl8259_1, al
;----- Enable 8250 Interrupt-on-data-ready
mov dx, [LCR] ; Read Line control register and clear
in al, dx ; bit 7, the Divisor Latch Address
and al, 07Fh
out dx, al
mov dx, [IER]
mov al, 3
out dx, al
;----- Clear 8250 Status and data registers
@@10:
mov dx, [RDR] ; Clear RDR by reading port
in al, dx
mov dx, [LSR] ; Clear LSR
in al, dx
mov dx, [MSR] ; Clear MSR
in al, dx
mov dx, [IIR] ; Clear IIR
in al, dx
test al, 1
jz @@10
;----- Set Bit 3 of MCR -- Enable interupts
mov dx, [MCR]
in al, dx
or al, 08h
out dx, al
;----- Clear Buffer Just in case
call _AsyncClear
;----- Return
pop bp
ret
ENDP _AsyncInit
;-----------------------------------------------------------------------------
; AsyncStop Uninstall ISR
;-----------------------------------------------------------------------------
; void AsyncStop( void)
;-----------------------------------------------------------------------------
PROC _AsyncStop
push bp
mov bp, sp
;----- Mask (disable) 8259 IRQ Interrupt
in al, Ctrl8259_1
or al, [DisableIRQ]
out Ctrl8259_1, al
;----- Disable 8250 interrupt
mov dx, [LCR]
in al, dx
and al, 07Fh
out dx, al
mov dx, [IER]
xor al, al
out dx, al
;----- Set bit 3 in MCR to 0
mov dx, [MCR]
in al, dx
and al, 0F7h
out dx, al
;----- Interrupts are disables. Restore saved interrupt vector.
push ds
mov al, [VectorNum]
mov ah, 25h
mov dx, [VectorOfs]
mov ds, [VectorSeg]
int 21h
pop ds
;----- Return
pop bp
ret
ENDP _AsyncStop
;-----------------------------------------------------------------------------
; AsyncISR Async Interrupt Service Routine
;-----------------------------------------------------------------------------
; To be called only as an interrupt.
;-----------------------------------------------------------------------------
PROC AsyncISR
push ax ; Save Registers
push bx
push ds
push dx
mov ax, @data ; Address local data with ds
mov ds, ax
mov dx, [IIR] ; Check if data actually recieved
in al, dx
and al, 06h
cmp al, 04h
je @@recieve
cmp al, 02h
jne @@end
;----- Transmit A byte
@@transmit:
mov bx, [TransTail]
cmp bx, [TransHead]
jne @@1
mov dx, [IER] ; Buffer empty
mov al, 1
out dx, al ; Disable THR empty interrupt
jmp @@end
@@1:
mov al, [byte ptr bx] ; Get Byte
inc [TransTail] ; Update buffer pointer
cmp [word ptr TransTail], offset TransBuffer + BufSize
jb @@2
mov [TransTail], offset TransBuffer
@@2:
mov dx, [THR]
out dx, al
jmp @@end
;----- Recieve a byte
@@recieve:
mov dx, [RDR] ; Get Byte
in al, dx
mov bx, [RecHead] ; Store Byte in buffer
mov [byte ptr bx], al
inc bx ; Update RecHead
cmp bx, offset RecBuffer + BufSize
jb @@10
mov bx, offset RecBuffer
@@10:
cmp bx, [RecTail]
jne @@20
mov bx, [RecHead] ; Cancel Pointer advance on overflow
@@20:
mov [RecHead], bx ; Store new pointer
@@end:
mov al, EOI ; Signal end ot interrupt
out Ctrl8259_0, al
pop dx
pop ds
pop bx
pop ax
iret
ENDP AsyncISR
;-----------------------------------------------------------------------------
; AsyncIn Gets a byte from the input buffer
;-----------------------------------------------------------------------------
; int AsyncIn( void)
;-----------------------------------------------------------------------------
PROC _AsyncIn
push bp
mov bp, sp
xor ax, ax ; Pre-Set result to 0
mov bx, [RecTail]
cmp bx, [RecHead]
je @@return
mov al, [byte ptr bx]
inc [RecTail]
cmp [word ptr RecTail], offset RecBuffer + BufSize
jb @@return
mov [RecTail], offset RecBuffer
@@return:
pop bp
ret
ENDP _AsyncIn
;-----------------------------------------------------------------------------
; AsyncOut Output a byte
;-----------------------------------------------------------------------------
; void AsyncOut( int c)
;-----------------------------------------------------------------------------
PROC _AsyncOut
ARG CharOut:word
push bp
mov bp, sp
mov ax, [CharOut]
mov bx, [TransHead]
mov cx, bx
inc cx ; Compute NEW buffer position
cmp cx, offset TransBuffer + BufSize
jb @@1
mov cx, offset TransBuffer
@@1:
cmp cx, [TransTail] ; Wait for space in buffer
je @@1
mov [byte ptr bx], al ; Add byte to buffer
mov [TransHead], cx ; Update pointer
mov dx, [IER] ; Enable THR empty interrupt
mov al, 3
out dx, al
pop bp
ret
ENDP _AsyncOut
;-----------------------------------------------------------------------------
; AsyncSet Set communication paramaters
;-----------------------------------------------------------------------------
; void AsyncSet( int Baud, int Control)
;
; Baud = 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 28800, 38400, 57600
; Control = The valure to place in the LCR
;-----------------------------------------------------------------------------
PROC _AsyncSet
ARG Baud:word, Control:word
push bp
mov bp, sp
mov bx, [Baud]
cmp bx, 0
je @@abort
mov ax, 0C200h ; Baud rate divisor = 115200 / Baud
mov dx, 0001h ; 115200 = 0001C200h
div bx
mov cx, ax
cli
mov dx, [LCR] ; Set Port Toggle to BRDL/BRDH registers
mov al, 0ffh
out dx, al
mov dx, [BRDL] ; Set Baud Rate
mov al, cl
out dx, al
mov dx, [BRDH]
mov al, ch
out dx, al
mov dx, [LCR] ; Set LCR and Port Toggle
mov ax, [Control]
and al, 07Fh
out dx, al
sti
@@abort:
pop bp
ret
ENDP _AsyncSet
;-----------------------------------------------------------------------------
; AsyncInStat Returns the # of characters in buffer
;-----------------------------------------------------------------------------
; int AsyncInStat( void)
;-----------------------------------------------------------------------------
PROC _AsyncInStat
push bp
mov bp, sp
mov ax,[RecHead]
sub ax, [RecTail]
jge @@10
add ax, BufSize
@@10:
pop bp
ret
ENDP _AsyncInStat
;-----------------------------------------------------------------------------
; AsyncOutStat Returns the # of characters in buffer
;-----------------------------------------------------------------------------
; int AsyncOutStat( void)
;-----------------------------------------------------------------------------
PROC _AsyncOutStat
push bp
mov bp, sp
mov ax,[TransHead]
sub ax, [TransTail]
jge @@10
add ax, BufSize
@@10:
pop bp
ret
ENDP _AsyncOutStat
;-----------------------------------------------------------------------------
; AsyncHand Sets various handshaking lines
;-----------------------------------------------------------------------------
; void AsyncHand( int Hand)
;-----------------------------------------------------------------------------
PROC _AsyncHand
ARG Hand:word
push bp
mov bp, sp
mov dx, [MCR]
mov ax, [Hand]
or al, 08h ; Keep interrupt enable ON
out dx, al
pop bp
ret
ENDP _AsyncHand
;-----------------------------------------------------------------------------
; AsyncStat Returns Async/Modem status
;-----------------------------------------------------------------------------
; unsigned AsyncStat( void)
;
; MSR is returned in the high byte, LSR in the low byte
;-----------------------------------------------------------------------------
PROC _AsyncStat
push bp
mov bp, sp
mov dx, [MSR]
in al, dx
mov cl, al
mov dx, [LSR]
in al, dx ; LSR in low byte
mov ah, cl ; MSR in high byte
pop bp
ret
ENDP _AsyncStat
END
-------------------------------The End--------------------------------------
--
David Kessner - david@kessner.denver.co.us | do {
1135 Fairfax, Denver CO 80220 (303) 377-1801 (p.m.) | . . .
This is my system so I can say any damn thing I want! | } while( jones);