home *** CD-ROM | disk | FTP | other *** search
- {$R-,S-}
- unit ComPort;
-
- interface
-
- uses TPDos,
- TpString,
- TpInt;
-
-
- function OpenCom(PortNum,Params: Word): boolean;
-
- { Issues interrupt $14 to initialize the UART, sets up buffers }
- { This procedure should be called using the const declarations following. }
- { Sample calling sequence: }
- { Port := Com1Port; }
- { Params := Baud9600 + NoParity + WordSize8 + StopBits1; }
- { if InitCom( Port, Params ) then; }
-
- function ComReady: boolean;
- {returns true if character ready; false if no character waiting }
-
- function ReadCom: char;
- {returns character from com port}
-
- procedure WriteCom( C: char );
- {Send a character}
-
- procedure WriteComStr( S: string );
- {Writes a string, S, by repeatedly calling WriteCom}
-
- const
- AsyncBufMax = 4095; {Upper limit of Async Buffer}
-
- var
- Async: record
- Overflow: boolean;
- PortNum,
- Base,
- Max,
- Head,
- Tail: word;
- Buffer: array[0..AsyncBufMax] of char;
- end;
-
- const
- Baud110 = $00;
- Baud150 = $20;
- Baud300 = $40;
- Baud600 = $60;
- Baud1200 = $80;
- Baud2400 = $A0;
- Baud4800 = $C0;
- Baud9600 = $E0;
- EvenParity = $18;
- OddParity = $08;
- NoParity = $00;
- WordSize7 = $02;
- WordSize8 = $03;
- StopBits1 = $04;
- StopBits2 = $00;
- Com1Port = $00;
- Com2Port = $01;
-
- {===========================================================================}
- {.pa}
- implementation
-
- const
- UART_THR = $00; {Transmit Hold Register}
- UART_RBR = $00; {Receive Buffer Register}
- UART_IER = $01; {Data ready interrupt}
- UART_IIR = $02; {}
- UART_LCR = $03; {}
- UART_MCR = $04; {OUT2}
- UART_LSR = $05; {Line Status Register}
- UART_MSR = $06; {}
- I8088_IMR = $21; {Interrupt Mask Register on 8250\9}
-
- var
- AsyncBIOSPortTable: array[1..2] of word absolute $40:0;
- SaveExitProc: pointer;
-
- procedure BiosInitCom(PortNum,Params: Word);
- inline(
- $58/ { POP AX ;Pop parameters }
- $5A/ { POP DX ;Pop port number }
- $B4/$00/ { MOV AH,0 ;Code for initialize }
- $CD/$14); { INT 14H ;Call BIOS }
-
- function InChar(PortNum: Word): Char;
- inline(
- $5A/ { POP DX ;Pop port number }
- $B4/$02/ { MOV AH,2 ;Code for input }
- $CD/$14); { INT 14H ;Call BIOS }
-
- function InReady(PortNum: Word): Boolean;
- inline(
- $5A/ { POP DX ;Pop port number }
- $B4/$03/ { MOV AH,3 ;Code for status }
- $CD/$14/ { INT 14H ;Call BIOS }
- $88/$E0/ { MOV AL,AH ;Get line status in AH }
- $24/$01); { AND AL,1 ;Isolate Data Ready bit }
-
- {$F+} procedure ComIntHandler( BP: word ); interrupt; {$F-}
-
- var
- Regs: IntRegisters absolute BP;
- NewHead: word;
-
- begin {ComIntHandler}
-
- with Async do begin
- Buffer[Head] := Chr( Port[UART_RBR + Base] );
- NewHead := succ( Head );
- if NewHead > Max then NewHead := 0;
- if NewHead = Tail then Overflow := true
- else Head := NewHead;
- InterruptsOff;
- Port[$20] := $20; {use non-specific EOI}
- end; {with Async}
-
- end; {ComIntHandler}
-
- function OpenCom(PortNum,Params: Word): boolean;
-
- const
- Handle = 15; {Select an arbitrary handle for TPInt}
-
- var
- IntNumber: byte;
- Junk,
- Mask: word;
- IRQ,
- Vector: byte;
- I: integer;
-
- begin
-
- if Async.PortNum <> $FFFF then begin
- OpenCom := false;
- exit;
- end;
- Async.Base := AsyncBIOSPortTable[PortNum + 1];
- IRQ := Hi(Async.Base) + 1;
- IntNumber := IRQ + $8;
- if (Port[UART_IIR + Async.Base] and $F8) <> 0 then begin
- OpenCom := false;
- exit;
- end;
- if not InitVector( IntNumber, Handle, @ComIntHandler ) then begin
- OpenCom := false;
- exit;
- end;
- Async.PortNum := PortNum;
- {Other parameters already initialized}
- BiosInitCom(PortNum,Params);
- InterruptsOff;
- Port[UART_LCR + Async.Base] := Port[UART_LCR + Async.Base] and $7F;
- Junk := Port[UART_LSR + Async.Base]; {Reset any Line Status Register errors}
- Junk := Port[UART_RBR + Async.Base]; {Empty Receive Buffer Register}
-
- {Enable IRQ on the 8259 controller}
- Port[I8088_IMR] := Port[I8088_IMR] and ((1 shl IRQ) xor $FF);
-
- Port[UART_IER + Async.Base] := $01; {Enable data ready interrupt on the 8250}
-
- {Enable OUT2 on 8250}
- Port[UART_MCR + Async.Base] := Port[UART_MCR + Async.Base] or $08;
- Port[$20] := $20; {clear out non-specific EOI}
-
- InterruptsOn;
- OpenCom := true;
-
- end;
-
- function ReadCom: char;
- {returns character from com port}
-
- begin
-
- with Async do begin
- repeat until Head <> Tail; {Wait here for a character}
- ReadCom := Buffer[Tail];
- InterruptsOff;
- Inc( Tail );
- if Tail > Max then Tail := 0;
- InterruptsOn;
- end;
-
- end; {ReadCom}
-
- function ComReady: boolean;
- {returns true if character ready; false if no character waiting }
-
- begin
-
- with Async do begin
- if Head = Tail then ComReady := false
- else ComReady := true;
- end;
-
- end; {ComReady}
-
- procedure WriteCom( C: char );
- {Send a character}
-
- var
- WaitCount: word;
-
- begin
-
- with Async do begin
- Port[UART_MCR + Base] := $0B; {Turn on OUT2, DTR, and RTS}
- WaitCount := $FFFF;
- while (WaitCount <> 0) and ((Port[UART_MSR + Base] and $10) = 0) do
- dec(WaitCount); {Wait for CTS (clear to send)}
- if WaitCount <> 0 then WaitCount := $FFFF;
- while (WaitCount <> 0) and ((Port[UART_LSR + Base] and $20) = 0) do
- dec(WaitCount); {Wait for THRE (transmit hold register empty)}
- if WaitCount <> 0 then begin
- InterruptsOff;
- Port[UART_THR + Base] := ord(C); {send the character}
- InterruptsOn;
- end;
- end;
-
- end; {WriteCom}
-
- procedure WriteComStr( S: string );
- {Writes a string, S, by repeatedly calling WriteCom}
-
- begin
-
- while length(S) > 0 do begin
- WriteCom( S[1] );
- S := copy( S, 2, 255 ); {throw away first character}
- end;
-
- end;
-
- procedure CloseCom;
-
- var
- IRQ: byte;
-
- begin
-
-
- if Async.PortNum <> $FFFF then begin
- IRQ := Hi(Async.Base) + 1;
- InterruptsOff;
- Port[I8088_IMR] := Port[I8088_IMR] or (1 shl IRQ); {Turn off int reqs}
- Port[UART_IER + Async.Base] := 0; {Disable 8250 Data ready interrupt}
- Port[UART_MCR + Async.Base] := 0; {Disable OUT2 on 8250}
- InterruptsOn;
- end;
-
- end; {CloseCom}
-
- {$F+} procedure ExitCom; {$F-}
-
- begin
-
- ExitProc := SaveExitProc;
- CloseCom;
-
- end;
- begin
-
- with Async do begin
- Overflow := false;
- PortNum := $FFFF;
- Max := AsyncBufMax;
- Head := 0;
- Tail := 0;
- end;
- SaveExitProc := ExitProc;
- ExitProc := @ExitCom;
-
- end.