resnicks@netcom.COM (Steve Resnick) (06/28/91)
Due to the number of requests for serial code, I am posting this driver
I wrote. It's for Turbo/Borland C.
Happy Hacking ....
Steve
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 06/05/1991 15:24 UTC by resnicks@netcom
# Source directory /u9/resnicks/sources/pc/asynch
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 11768 -rw-r--r-- asynch.c
# 3229 -rw-r--r-- asynch.h
# 2692 -rw-r--r-- circleq.c
# 336 -rw-r--r-- circleq.h
# 838 -rw-r--r-- main.c
# 270 -rw-r--r-- makefile
#
# ============= asynch.c ==============
if test -f 'asynch.c' -a X"$1" != X"-c"; then
echo 'x - skipping asynch.c (File already exists)'
else
echo 'x - extracting asynch.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'asynch.c' &&
/*
X * ASYCNCH.C A simple, low-level, interrupt driven comm driver for
X * Turbo/Borland C. No assembly required!
X *
X * (C) Copyright 1991 Steve Resnick, Asylum Software. All Rights Reserved.
X *
X * Steve Resnick - 530 Lawrence Expressway, Box 374, Sunnyvale, Ca 94086
*/
#include <stdio.h>
#include <dos.h>
#include "asynch.h"
/*
X * This table is used to translate a BPS rate to a baud rate divisor for the
X * UART
*/
struct _baud
{
X word Rate, Divisor;
} BaudTable[] =
{
X 110,1040,150,768,300,384,600,192,1200,96,2400,48,4800,24,9600,12,
X 19200,6, /* I have no idea if this works */
} ;
#if DEBUG
byte PICVals[2][2]; /* Mirror PIC values to these arrays */
byte DataTable[2][20]; /* Mirror UART values to these arrays */
byte portinb(word port); /* Use our own port I/O functions */
void portoutb(word port, byte data);
#else
#define portinb(p) inportb(p)
#define portoutb(p,b) outportb(p,b)
#endif
uart cports[4] = {COM1_DEFAULTS,COM2_DEFAULTS};
X
/*
X * SetPortParms sets up the UART line parameters and baud rate.
X * If Base, IRQ, and BreakLength are specified as 0, defaults are used.
X * (See ASYNCH.H)
X * This may only be called for an open port.
*/
int SetPortParms(int PortNo, int Baud, int Parity, int Data, int Stop,
X int Base, int IRQ, int BreakLength)
{
X int i, b;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X
X if (Base)
X cports[PortNo].addr = Base;
X if (IRQ)
X cports[PortNo].irqline = IRQ;
X if (BreakLength)
X cports[PortNo].break_length = BreakLength;
X
X cports[PortNo].parms = 0;
X cports[PortNo].parms |= Data;
X cports[PortNo].parms |= Stop;
X cports[PortNo].parms |= Parity;
X if (Baud != 0)
X {
X for (i = 0, b = -1; i < dim(BaudTable); i++)
X if (BaudTable[i].Rate == Baud)
X b = i;
X if (b == -1)
X return EINVBAUDRATE;
X
X cports[PortNo].baud = BaudTable[b].Divisor;
X InitBaud(PortNo);
X }
X else if (cports[PortNo].baud == 0)
X return EINVBAUDRATE;
X portoutb(cports[PortNo].addr+LCR_REG,cports[PortNo].parms);
X return 0;
}
/*
X * copen opens a comm port spcified by PortNo. Input and Output buffers are
X * allocated according to the BufSiz parameter.
X * If Base, IRQ, and BreakLength are specified as 0, defaults are used.
X * (See ASYNCH.H)
X *
X * When the port is opened, the following takes place:
X * Buffer memory is allocated
X * CommPort options are set
X * The interrupt vector is set based on IRQ+8
X * The 8259 is enabled to recieve interrupts.
X * The 8250 IE mask is set
X * The 8250 OUT2 is asserted, enabling the interrupt line from the UART to the
X * PIC.
*/
int copen(int PortNo, int BufSiz, int Baud, int Parity, int Data, int Stop,
X int Base, int IRQ, int BreakLength)
{
X uart * Cp;
X int Rc;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED)
X return EPORTALREADYOPEN;
X Cp = &cports[PortNo];
X if ((Cp->InBuffer = Qalloc(BufSiz)) == NULL)
X return EMEMALLOC;
X if ((Cp->OutBuffer = Qalloc(BufSiz)) == NULL)
X {
X Qfree(Cp->InBuffer);
X return EMEMALLOC;
X }
X Cp->status |= PS_ENABLED;
X Rc = SetPortParms(PortNo,Baud,Parity,Data,Stop,Base,IRQ,BreakLength);
X if (Rc)
X {
X Qfree(Cp->InBuffer);
X Qfree(Cp->OutBuffer);
X Cp->status = 0;
X return Rc;
X }
X SetIntVector(PortNo);
X disable();
X SetPIC(PortNo,1);
X SetUARTIe(PortNo);
X enable();
X ControlDTR(PortNo,ON);
X return 0;
}
/*
X * cclose closes a serial port by disabling interrupts on the UART, then on
X * the PIC and finally, returns the original vector to the IVT.
*/
int cclose(int PortNo)
{
X uart * Cp;
X int Rc;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X Cp = &cports[PortNo];
X disable();
X ClrIntVector(PortNo);
X SetPIC(PortNo,0);
X enable();
X Cp->status = 0;
X Qfree(Cp->InBuffer);
X Qfree(Cp->OutBuffer);
X portoutb(Cp->addr + IE_REG,0);
X portoutb(Cp->addr + MCR_REG,1);
X return 0;
}
/*
X * InitBaud sets the baudrate on the UART by setting the divisor latch access
X * bit (DLAB) then writing the divisor's low byte,then the divisors high byte.
X * For baudrates >= 600 BPS, the high byte should be 0. (See ASYNCH.H)
*/
int InitBaud(int PortNo)
{
X uart * Cp;
X byte bdata;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X Cp = &cports[PortNo];
X bdata = portinb(Cp->addr + LCR_REG);
X portoutb(Cp->addr + LCR_REG,bdata | DLAB);
X portoutb(Cp->addr + DIV_LOW,LOBYTE(Cp->baud));
X portoutb(Cp->addr + DIV_HI, HIBYTE(Cp->baud));
X portoutb(Cp->addr + LCR_REG,Cp->parms);
X return 0;
}
/*
X * SetPIC sets or clears the interrupt enable mask on the PIC for a
X * particular interrupt. This function will work for both the master
X * and the slave 8259A's in an AT.
*/
SetPIC(int PortNo, int State)
{
static int States[] = {-1,-1,-1,-1};
X int PICAddr = PIC;
X byte mask;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if(State == 0 && States[PortNo] == -1)
X return -1;
X if (cports[PortNo].irqline > 7)
X {
X mask = ( 1 << (cports[PortNo].irqline - 8));
X PICAddr = 0xA0;
X }
X else
X mask = (1 << cports[PortNo].irqline);
X
X if (State == 0)
X {
X States[PortNo] = portinb(PIC+1);
X portoutb(PICAddr+1,(byte)States[PortNo]|mask);
X return 0;
X }
X mask = ~mask;
X States[PortNo] = portinb(PICAddr+1);
X portoutb(PICAddr+1,States[PortNo] & mask);
X portinb(PICAddr+1);
X return 0;
}
/*
X * EOI Sends a non-specific end of interrupt to the 8259A specific to the
X * IRQ line of a com port
*/
int EOI(int PortNo)
{
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X if (cports[PortNo].irqline > 7)
X portoutb(0xA0,0x20);
X else
X portoutb(0x20,0x20);
X return 0;
}
/*
X * This is the interrupt handler for ALL comm ports. Each ISR for a comm
X * port calls this routine passing the index into the UART definition array
X * so that values may be extracted for things like UART address, etc.
X *
X * This is a re-entrant function, although interrupts are disabled to ensure
X * that interrupts are handled one at a time for each UART. This may be
X * over-kill and may need to be changed in the future.
*/
void IsrHandler(int PortNo)
{
X uart * Cp;
X byte Idv, IIDvalue=0;
X disable();
X Cp = &cports[PortNo];
X IIDvalue = portinb(Cp->addr+ IID_REG);
X if ((IIDvalue & IID_PENDING) == 0)
X {
X IIDvalue &= IID_MASK ;
X Idv = IIDvalue >> 1;
X if (Idv & IID_DATA)
X QinsertChar(Cp->InBuffer,portinb(Cp->addr));
X
X if (Idv & IID_TEMPTY)
X DrainOutQueue(PortNo);
X
X if (Idv & IID_LSTAT)
X Cp->lstat = portinb(Cp->addr+ LSR_REG);
X
X if (Idv & IID_MSTAT)
X Cp->mstat = portinb(Cp->addr+ MSR_REG);
X
X portinb(Cp->addr+5);
X portinb(Cp->addr+6);
X }
X enable();
X SetUartOUT2(PortNo);
X EOI(PortNo);
}
/*
X * Dummy ISR's
X * Each comm port needs to have it's own ISR, but we need only one real
X * handler. Since an ISR shared my multiple interrupts cannot determine
X * it's source, we set up these dummy ISR's to call IsrHandler specifying
X * the port which needs service.
*/
void interrupt com1isr()
{
X IsrHandler(0);
}
void interrupt com2isr()
{
X IsrHandler(1);
}
void interrupt com3isr()
{
X IsrHandler(2);
}
void interrupt com4isr()
{
X IsrHandler(3);
}
/*
X * SetIntVector sets the appropriate interrupt vector (correctly for both
X * (master and slaved IRQ's) based on the IRQ. The original vector is saved
X * in the UART structure so that it may be reset upon termination.
*/
SetIntVector(int PortNo)
{
X int NewInt;
static void interrupt (*isrs[])() = {com1isr,com2isr,com3isr,com4isr};
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X cports[PortNo].oldisr = getvect(IRQINT(cports[PortNo].irqline));
X NewInt = IRQINT(cports[PortNo].irqline);
X setvect(NewInt,isrs[PortNo]);
X return 0;
}
/*
X * ClrIntVector revectors interrupts back to the original vector before we
X * loaded up.
*/
ClrIntVector(int PortNo)
{
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X setvect(IRQINT(cports[PortNo].irqline),cports[PortNo].oldisr);
X return 0;
}
/*
X * SetUARTIe sets the interrupt enable mask on the UART.
X * SetUartOUT2 is then called to unmask interrupts from the UART to the PIC
*/
SetUARTIe(int PortNo)
{
X int i;
X word IntFlags = IIV_LSTAT | IIV_RDATA | IIV_MSTAT | IIV_XMITE;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X for (i = 5; i < 8; i++)
X inportb(cports[PortNo].addr+i);
X
X portoutb(cports[PortNo].addr + IE_REG, IntFlags);
X SetUartOUT2(PortNo);
X return 0;
}
/*
X * SetUARTOut2 set's the OUT2 line on the UART high, allowing interrupts
X * to pass from the UART to the PIC (thanks, IBM)
*/
SetUartOUT2(int PortNo)
{
X byte IoData;
X IoData = portinb(cports[PortNo].addr + MCR_REG);
X portoutb(cports[PortNo].addr + MCR_REG,IoData | UARTIEMASK);
X return 0;
}
/*
X * DrainOutQueue reads characters from the output queue to the UART, as
X * long as the UART is ready for data. If it is not ready, we return
X * immediately.
*/
DrainOutQueue(int PortNo)
{
X byte IoData;
X char Ch;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X
X while(1)
X {
X IoData = portinb(cports[PortNo].addr + LSR_REG);
X if (IoData & 0x20 || IoData & 0x40)
X {
X Ch = QreadChar(cports[PortNo].OutBuffer);
X if (Ch == -1)
X break ;
X portoutb(cports[PortNo].addr,Ch);
X continue ;
X }
X break ;
X }
X return 0;
}
/*****************************************************************************
X ****************************** User Functions ******************************/
/*
X * cgetc reads a character from the input queue and returns it, or -1 if no
X * character is available.
*/
cgetc(int PortNo)
{
X if (PortNo > 3 || PortNo < 0)
X return -10 - EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return -10 - EPORTNOTOPEN;
X return QreadChar(cports[PortNo].InBuffer);
}
/*
X * cputc writes a character to the output queue
*/
cputc(int PortNo, char Ch)
{
X if (PortNo > 3 || PortNo < 0)
X return -10 - EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return -10 - EPORTNOTOPEN;
X
X QinsertChar(cports[PortNo].OutBuffer,Ch);
X DrainOutQueue(PortNo);
X return 0;
}
/*
X * SendBreak sets a break condition on the serial line and holds it
X * for break_lenght miliseconds
*/
int SendBreak(int PortNo)
{
X byte IoData;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X IoData = portinb(cports[PortNo].addr + LCR_REG);
X portoutb(cports[PortNo].addr + LCR_REG,IoData | 0x40);
X delay(cports[PortNo].break_length);
X portoutb(cports[PortNo].addr + LCR_REG,IoData);
X return 0;
}
/*
X * ControlDTR raises or lowers DTR on a specific port
*/
int ControlDTR(int PortNo, int State)
{
X byte IoData;
X if (PortNo > 3 || PortNo < 0)
X return EINVPORT;
X if (cports[PortNo].status & PS_ENABLED == 0)
X return EPORTNOTOPEN;
X IoData = portinb(cports[PortNo].addr + MCR_REG);
X if (State == ON)
X portoutb(cports[PortNo].addr + MCR_REG,(byte)(IoData | 1));
X else
X portoutb(cports[PortNo].addr + MCR_REG,(byte)(IoData & ~1)&0xFF);
X return 0;
}
/******************************************************************************
****************************** Debugging Functions ***************************/
#if DEBUG
void portoutb(word port, byte data)
{
X int Idx = port - 0x3f8;
X if (Idx > -1 && Idx < 20)
X DataTable[0][Idx] = data;
X if (port >0x1F && port < 0x22)
X {
X Idx = port - 0x20;
X PICVals[0][Idx] = data;
X }
X outportb(port,data);
}
byte portinb(word port)
{
X int Idx = port - 0x3F8;
X byte Data;
X Data = inportb(port);
X if (port >0x1F && port < 0x22)
X {
X Idx = port - 0x20;
X PICVals[1][Idx] = Data;
X }
X else if (Idx > -1 && Idx < 20)
X DataTable[1][Idx] = Data;
X return Data;
}
#endif
X
X
SHAR_EOF
chmod 0644 asynch.c ||
echo 'restore of asynch.c failed'
Wc_c="`wc -c < 'asynch.c'`"
test 11768 -eq "$Wc_c" ||
echo 'asynch.c: original size 11768, current size' "$Wc_c"
fi
# ============= asynch.h ==============
if test -f 'asynch.h' -a X"$1" != X"-c"; then
echo 'x - skipping asynch.h (File already exists)'
else
echo 'x - extracting asynch.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'asynch.h' &&
#if !defined(ASYNCH_INCLUDED) /* Prevent multiple includes */
#define ASYNCH_INCLUDED
#include "circleq.h"
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
typedef struct _lcr
{
X word databits : 2;
X word stopbits : 1;
X word parity : 2;
X word stuckparity : 1;
X word breakenable : 1;
X word dlab : 1;
} lcr;
typedef struct _uart
{
X word addr;
X byte irqline;
X word baud;
X byte lstat;
X
X byte mstat;
X byte status;
X byte break_length;
X byte parms;
X CircleQ *InBuffer;
X CircleQ *OutBuffer;
X void interrupt (*oldisr)();
} uart;
#define LineStatus(n) ((n >= 0 && n <4) ? cports[n].lstat : EINVPORT)
#define ModemStatus(n) ((n >= 0 && n <4) ? cports[n].mstat : EINVPORT)
X
extern uart cports[4];
#define COM1_DEFAULTS\
X {0x3F8,4,0,0,0,0,250,\
X DATA8|STOP1|NONE,\
X NULL,NULL}
X
#define COM2_DEFAULTS \
X {0x2F8,3,0,0,0,0,250,\
X DATA8|STOP1|NONE,\
X NULL,NULL}
X
#define PIC 0x20 /* 8259A PIC Address */
#define IRQINT(n) ((n < 9) ? n+8 : (n-9)+0x70)
X /* Make int value from IRQ */
#define IID(n) (n & 7) /* Get Interrupt ID from reg val */
/*
X * Define Interrupt ID values from the interrupt ID register
*/
#define IID_PENDING 0x01
#define IID_LSTAT 0x00 /* Line status change */
#define IID_DATA 0x02 /* Data is available from 8250 */
#define IID_TEMPTY 0x04 /* Transmitter buffer empty */
#define IID_MSTAT 0x06 /* New modem status */
#define IID_MASK 0x07
X
#define IIV_LSTAT 0x01
#define IIV_XMITE 0x02
#define IIV_RDATA 0x04
#define IIV_MSTAT 0x08
/*
X * Define some offsets from the UART base address for various registers
*/
#define XMT_REG 0x00 /* Transmitter holding buffer */
#define RCV_REG 0x00 /* Reciever holding buffer */
#define DIV_LOW 0x00 /* Divisor low byte when DLAB=1 */
#define DIV_HI 0x01 /* Devisor high byte when DLAB=1 */
X
#define IE_REG 0x01 /* Interrupt enable register */
#define IID_REG 0x02 /* Interrupt ID register */
#define LCR_REG 0x03 /* line control register */
#define MCR_REG 0x04 /* Modem control register */
#define LSR_REG 0x05 /* line status register */
#define MSR_REG 0x06 /* modem status register */
X
/*
X * Stuff for the line control register
*/
#define NONE 0x00 /* No Parity */
#define ODD 0x08 /* Odd Parity */
#define EVEN 0x18 /* Even Parity */
#define STOP1 0x00 /* Need I explain these? */
#define STOP2 0x04
#define DATA5 0x00
#define DATA6 0x01
#define DATA7 0x02
#define DATA8 0x03
#define DLAB 0x80
X
#define UARTIEMASK 0x08 /* Mask used to enable interrupts on
X the 8250 OUT2 line */
#define PS_ENABLED 0x01
#define PS_INTERRUPT 0x02 /* Not used */
X
enum errors {EPORTNOTOPEN=1,EPORTALREADYOPEN,EINVBAUDRATE,EINVPORT,EMEMALLOC};
#define COM1 0
#define COM2 1
#define ON 1
#define OFF 0
#define HIBYTE(n) ((n >> 8) & 0xFF)
#define LOBYTE(n) (n & 0xFF)
X
#if !defined(dim)
#define dim(x) (sizeof(x)/sizeof(x[0]))
#endif
int SetPortParms(int PortNo, int Baud, int Parity, int Data, int Stop,
X int Base, int IRQ, int BreakLength);
int copen(int PortNo, int BufSiz, int Baud, int Parity, int Data, int Stop,
X int Base, int IRQ, int BreakLength);
int cclose(int PortNo);
int InitBaud(int PortNo);
SetPIC(int PortNo, int State);
cgetc(int PortNo);
cputc(int PortNo, char Ch);
X
#endif
X
SHAR_EOF
chmod 0644 asynch.h ||
echo 'restore of asynch.h failed'
Wc_c="`wc -c < 'asynch.h'`"
test 3229 -eq "$Wc_c" ||
echo 'asynch.h: original size 3229, current size' "$Wc_c"
fi
# ============= circleq.c ==============
if test -f 'circleq.c' -a X"$1" != X"-c"; then
echo 'x - skipping circleq.c (File already exists)'
else
echo 'x - extracting circleq.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'circleq.c' &&
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "circleq.h"
X
/*
X * Qalloc allocates space for a Queue Control Structure (CircleQ) and
X * a buffer to be contained within.
X * If space is not available for this structure, or it's buffer, NULL
X * is returned, otherwise a pointer to a CirclQ is returned.
*/
CircleQ * Qalloc(int Size)
{
X CircleQ * Qptr;
X if ((Qptr = calloc(sizeof(CircleQ),1)) == NULL)
X {
X errno = ENOMEM;
X return NULL;
X }
X if ((Qptr->Buffer = calloc(Size,1)) == NULL)
X {
X free(Qptr);
X errno = ENOMEM;
X return NULL ;
X }
X Qptr->Head = Qptr->Tail = Qptr->Buffer;
X Qptr->Size = Size;
X return Qptr;
}
/*
X * QinsertChar inserts a character on a queue. The tail pointer is used
X * to indicate where the character shall be placed. Once a character is
X * written, the tail pointer is updated. If the tail pointer overruns the
X * head pointer, the overrun flag is set. Once the overrun flag is set, the
X * head pointer will be updated on all subsequent writes to ensure that
X * the buffer always contains Qptr->Size characters. If Qptr->Tail or
X * Qptr->Head reach the end of the buffer, they are wrapped around to
X * the beginning of the buffer.
*/
void QinsertChar(CircleQ * Qptr, char Ch)
{
X *Qptr->Tail = Ch;
X if ((Qptr->Tail + 1) >= (Qptr->Buffer+Qptr->Size))
X Qptr->Tail = Qptr->Buffer;
X else
X Qptr->Tail ++;
X
X if (Qptr->Head == Qptr->Tail)
X Qptr->Flag = 1; /* Queue buffer overflow */
X
X if (Qptr->Flag)
X Qptr->Head ++ ;
X if (Qptr->Head >= Qptr->Buffer + Qptr->Size)
X Qptr->Head = Qptr->Buffer;
}
/*
X * QpeekChar returns a character from the specified queue without removing
X * it. If the queue is empty -1 is returned.
*/
char QpeekChar(CircleQ * Qptr)
{
X if (Qptr->Head == Qptr->Tail)
X {
X Qptr->Flag = 0;
X return -1;
X }
X return *Qptr->Head;
}
/*
X * QreadChar returns a character from the specified queue. The queue is then
X * updated to reflect the last read. If the queue is empty, -1 is returned.
*/
char QreadChar(CircleQ * Qptr)
{
X char Ch = -1;
X if (Qptr->Head == Qptr->Tail)
X {
X Qptr->Flag = 0;
X return -1;
X }
X Ch = *Qptr->Head;
X Qptr->Head ++ ;
X if (Qptr->Head >= Qptr->Buffer + Qptr->Size)
X Qptr->Head = Qptr->Buffer;
X return Ch;
}
/*
X * Qfree frees a queue control structure (CircleQ) and all buffers
X * associated with it (Qptr->Buffer). This Head and Tail pointers are
X * set to NULL, and Size and Flag (overrun flag) are set to 0.
X * Qptr is then freed, releasing all memory associated with the queue.
X * No subsequent operations may be made on this queue.
*/
void Qfree(CircleQ * Qptr)
{
X if (Qptr != NULL)
X {
X free(Qptr->Buffer);
X Qptr->Buffer = Qptr->Head = Qptr->Tail = NULL;
X Qptr->Size = Qptr->Flag = 0;
X free(Qptr);
X }
}
X
SHAR_EOF
chmod 0644 circleq.c ||
echo 'restore of circleq.c failed'
Wc_c="`wc -c < 'circleq.c'`"
test 2692 -eq "$Wc_c" ||
echo 'circleq.c: original size 2692, current size' "$Wc_c"
fi
# ============= circleq.h ==============
if test -f 'circleq.h' -a X"$1" != X"-c"; then
echo 'x - skipping circleq.h (File already exists)'
else
echo 'x - extracting circleq.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'circleq.h' &&
#if !defined(CIRCLEQ_INCLUDE)
#define CIRCLEQ_INCLUDE
typedef struct _circq
{
X char * Head;
X char * Tail;
X char * Buffer;
X int Size;
X int Flag;
} CircleQ;
X
CircleQ * Qalloc(int size);
void Qfree(CircleQ * qptr);
void QinsertChar(CircleQ * qptr, char ch);
char QpeekChar(CircleQ * qptr);
char QreadChar(CircleQ * qptr);
#endif
X
SHAR_EOF
chmod 0644 circleq.h ||
echo 'restore of circleq.h failed'
Wc_c="`wc -c < 'circleq.h'`"
test 336 -eq "$Wc_c" ||
echo 'circleq.h: original size 336, current size' "$Wc_c"
fi
# ============= main.c ==============
if test -f 'main.c' -a X"$1" != X"-c"; then
echo 'x - skipping main.c (File already exists)'
else
echo 'x - extracting main.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
#include <stdio.h>
#include <conio.h>
#include "asynch.h"
void Beep(void);
int ctrlc(void)
{
X cputc(COM2,3);
X return 1;
}
main()
{
X int RetCode, c;
X if((RetCode = copen(COM2,2048,2400,NONE,DATA8,STOP1,0,0,0)) != 0)
X {
X printf("copen failed: Code: %d\n",RetCode);
X return -1;
X }
X clrscr();
X ctrlbrk(ctrlc);
X fclose(stdout);
X while(1)
X {
X if (kbhit())
X {
X c = getch();
X if (c == 0)
X {
X switch(getch()&0xFF)
X {
X case 68 :
X cclose(COM2);
X return 0;
X case 35 :
X ControlDTR(COM2,OFF);
X delay(500);
X ControlDTR(COM2,ON);
X break ;
X case 48 :
X SendBreak(COM2);
X break ;
X default :
X Beep();
X break;
X }
X
X }
X else
X cputc(COM2,c);
X }
X if ((c = cgetc(COM2)) >= 0)
X fprintf(stderr,"%c",c);
X }
}
void Beep()
{
X sound(1000);
X delay(250);
X nosound();
}
X
X
SHAR_EOF
chmod 0644 main.c ||
echo 'restore of main.c failed'
Wc_c="`wc -c < 'main.c'`"
test 838 -eq "$Wc_c" ||
echo 'main.c: original size 838, current size' "$Wc_c"
fi
# ============= makefile ==============
if test -f 'makefile' -a X"$1" != X"-c"; then
echo 'x - skipping makefile (File already exists)'
else
echo 'x - extracting makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
X
!if $d(DEBUG)
objs=asynch.obj circleq.obj test.obj
cargs=-ms -v -DDEBUG=1
X
test.exe: $(objs)
X cc $(cargs) -etest.exe $(objs)
!else
objs=asynch.obj circleq.obj main.obj
cargs=-ms -v
X
term.exe: $(objs)
X cc $(cargs) -eterm.exe $(objs)
!endif
X
.c.obj:
X cc -c $(cargs) $<
X
X
SHAR_EOF
chmod 0644 makefile ||
echo 'restore of makefile failed'
Wc_c="`wc -c < 'makefile'`"
test 270 -eq "$Wc_c" ||
echo 'makefile: original size 270, current size' "$Wc_c"
fi
exit 0
--
-------------------------------------------------------------------------------
resnicks@netcom.com, steve@camphq, IFNA: 1:143/105.0,
co moderator for comp.binaries.os2
Real life: Steve Resnick. Chief Software Architect, Process Scientific, Inc
Flames, grammar and spelling errors >/dev/null
The Asylum OS/2 BBS - (408)263-8017 12/2400,8,1 - Running Maximus CBCS 1.2
-------------------------------------------------------------------------------