almquist@brahms.udel.edu (Squish) (03/12/91)
Anyone out there have some example source code, samples, docs, help, etc. on programming the serial ports on a PC? Thanks! - Mike Almquist (almquist@brahms.udel.edu)
davem@hpmwtd.HP.COM (Dave McQuate) (03/14/91)
Here's a re-post from 26 Feb 1991 comp.os.msdos.programmer-- From david@kessner.denver.co.us Mon Feb 25 23:04:43 1991 Relay-Version: version Notes 2.8.2 (with RFA) 87/11/24; site hpmwdjm.HP.COM From: david@kessner.denver.co.us (David D. Kessner) Date: Tue, 26 Feb 1991 07:04:43 GMT Date-Received: Tue, 26 Feb 1991 21:31:18 GMT Subject: Serial routines Message-ID: <1991Feb26.070443.7470@kessner.denver.co.us> Organization: Kessner, Inc Path: hpmwdjm!hpnmdla!hpl-opus!hplabs!sdd.hp.com!zaphod.mps.ohio-state.edu!magnus.ircc.ohio-state.edu!csn!kessner!david Newsgroups: comp.os.msdos.programmer Sender: david@kessner.denver.co.us (David Kessner) Keywords: C ASSEMBLER TURBO SERIAL MODEM Lines: 656 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);