home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_09_12
/
9n12075a
< prev
next >
Wrap
Text File
|
1991-07-27
|
17KB
|
443 lines
/** LISTING 3 ** UARTLOW.C ***************************
Low level device driver routines for UART
*****************************************************/
#define UARTMAIN 1
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <dos.h>
#include "uart.h"
#include "uartmacs.c"
/*
* Compile Options : /AL /Ox /Zp /c
* (Large library, optimization
* for maxium speed, pack structures).
* Note: /Ox does the following optimizations
* Relaxed alias checking
* Loop optimization
* Intrinsic substitution
* Optimization for speed
* Removing stack probing
*/
#pragma check_stack(off)
void interrupt far Asynch_driver(void)
{
register int value_from_port;
register int cur_char;
static unsigned char near cur_port;
static struct t_port_info *p_cur_port_info;
static int near interrupts_processed;
static int near i;
static char *p_temp;
static char tx_char;
/* Note - interrupts are automatically disabled by
CPU before entering interrupt routine. */
do
{ /* Loop until we make one complete pass
without processing any interrupts */
/* Set flag indicating that we haven't
processed any interrupts on this pass
through the loop yet. */
interrupts_processed = 0;
/* Address the port entry of the first port in
the system. */
p_cur_port_info = gp_port_info;
for (cur_port=1;cur_port<=g_num_ports;
cur_port++)
{ /* Loop through all the ports */
/* read port's interrupt identification register */
value_from_port = inp(p_cur_port_info->
base_address+INTERRUPT_IDENT_REGISTER);
if ( value_from_port & 0x01 )
{ /* No interrupt pending */
/* If less than MAX_RCVFIFO characters
have been read without receiving a
receive data interrupt, check line
status register to see if there is
still data in the FIFO. This code
will function correctly even if there
isn't a FIFO. */
if (p_cur_port_info->non_int_chars <
MAX_RCVFIFO)
{
/* read port's line status register */
value_from_port =
inp(p_cur_port_info->
base_address +
LINE_STATUS_REGISTER);
/* Delay for port to catch up */
IO_DELAY(1);
if ( value_from_port & 0x01 )
{ /* Data is ready */
/* Increment number of chars
processed from fifo without
interrupt */
p_cur_port_info->
non_int_chars++;
/* We have found at least one
interrupt pending so we will
have to make at least one
more pass. */
interrupts_processed = 1;
/* Skip normal interrupt
identification logic, and go
right to reading the data. */
goto force_read_data;
} /* End data is ready */
} /* End p_cur_port_info->
non_int_chars < MAX_RCVFIFO) */
} /* end no interrupt pending */
else
{ /* There is an interrupt pending
from this port */
/* We have found at least one interrupt
pending so we will have to make at
least one more pass. */
interrupts_processed = 1;
/* Mask out unwanted bits from interrupt
identification. */
value_from_port &= IIR_MASK;
switch (value_from_port)
{ /* Conditional execution depending
on type of interrupt */
/* Interrupt for Receiver Line
Status */
case 0x06 :
/* Clear receive register */
cur_char =
inp(p_cur_port_info->
base_address +
RECEIVE_REGISTER);
/* Clear high word of character
before breaking down error */
cur_char &= 0x00ff;
/* read port's line status
register */
value_from_port =
inp(p_cur_port_info->
base_address +
LINE_STATUS_REGISTER);
if (value_from_port & 0x10)
{ /* Received 'break' */
cur_char |= BREAK_SIGNAL;
}
if (value_from_port & 0x08)
{ /* framing error */
cur_char |= FRAMING_ERROR;
}
if (value_from_port & 0x04)
{ /* parity error */
cur_char |= PARITY_ERROR;
}
if (value_from_port & 0x02)
{ /* overrun error */
cur_char |= OVERRUN_ERROR;
}
goto add_char_to_rx_buf;
/* Interrupt for data received */
case 0x04 :
/* Check line status register to
see if data is ready */
value_from_port =
inp(p_cur_port_info->
base_address +
LINE_STATUS_REGISTER);
if ( !(value_from_port & 0x01) )
break;
/* Set number of characters
received without data receive
interrupt to 0. */
p_cur_port_info->
non_int_chars = 0;
force_read_data:
/* read received data
register */
cur_char =
inp(p_cur_port_info->
base_address+
RECEIVE_REGISTER);
/* Clear high word of character
before breaking down error */
cur_char &= 0x00ff;
add_char_to_rx_buf:
/* Calculate pointer to next
position in circular
receive buffer */
p_temp = p_cur_port_info->
a_receive_buffer +
p_cur_port_info->rx_tail;
/* Calculate next tail position
in receive buffer */
p_cur_port_info->rx_tail += 2;
if (p_cur_port_info->rx_tail >=
(BUFFER_SIZE * 2) )
p_cur_port_info->rx_tail = 0;
/* Check for receive buffer
overflow */
if (p_cur_port_info->rx_tail ==
p_cur_port_info->rx_head)
{ /* Receive buffer has
overflowed. Update
flag to reflect this,
and advance head
(losing one char). */
cur_char |=
BUFFER_OVERRUN;
p_cur_port_info->rx_head
+= 2;
if (p_cur_port_info->
rx_head >=
(BUFFER_SIZE * 2) )
p_cur_port_info->
rx_head = 0;
}
/* Add character with coded
error condition flag to
circular buffer */
*( (int *) p_temp) = cur_char;
break;
/* Interrupt for Transmit Holding
Register Emtpy */
case 0x02 :
if (p_cur_port_info->tx_head !=
p_cur_port_info->tx_tail )
{ /* Have data to transmit */
if (p_cur_port_info->
obey_rts_cts &&
!p_cur_port_info->
cts_state)
{ /* Require Clear To
Send before
transmitting */
/* Raise the Request To
Send signal */
RAISE_RTS;
break;
}
/* read port's line status
register */
value_from_port =
inp(p_cur_port_info->
base_address +
LINE_STATUS_REGISTER);
/* Delay for port to catch
up */
IO_DELAY(2);
/* Make sure transmit
holding register is
really empty. */
if ( !(value_from_port
& 0x20) )
break;
/* Transmit as many chars as
port can handle (depends
on presence/absence of
fifo), until transmit
circular buffer is
empty */
for (i=0;
(i<p_cur_port_info->
max_tx_chars) &&
(p_cur_port_info->
tx_head !=
p_cur_port_info->
tx_tail ) ;
i++)
{
/* Get next character
to transmit and
increment transmit
data pointer. */
tx_char =
p_cur_port_info->
a_transmit_buffer[
p_cur_port_info->
tx_head++];
if (p_cur_port_info->
tx_head >=
BUFFER_SIZE)
p_cur_port_info->
tx_head = 0;
/* Transmit the
character */
outp(p_cur_port_info->
base_address +
TRANSMIT_REGISTER,
tx_char);
} /* End for TX loop */
} /* end if data to
transmit */
else
{ /* No data to send */
if (p_cur_port_info->
obey_rts_cts)
{ /* No data to send, port
is using flow
control */
/* Turn off the Request
To Send signal */
DROP_RTS;
}
} /* End no data to send */
break;
/* Interrupt for modem status
change */
case 0x00 :
/* read port's modem status
register */
value_from_port =
inp(p_cur_port_info->
base_address +
MODEM_STATUS_REGISTER);
if (value_from_port & 0x02)
{ /* Change in Data Set Ready */
if (IS_DSR(value_from_port))
/* DSR came on */
p_cur_port_info->
dsr_state = 1;
else
/* DSR went off */
p_cur_port_info->
dsr_state = 0;
} /* End if delta data set ready */
if (value_from_port & 0x08)
{ /* Change In Data Carrier Detect */
if (IS_DCD(value_from_port))
/* DCD came on */
p_cur_port_info->
dcd_state = 1;
else
/* DCD went off */
p_cur_port_info->
dcd_state = 0;
} /* End if delta carrier detect */
if (value_from_port & 0x01)
{ /* Change in Clear To Send */
if (IS_CTS(value_from_port))
{
/* CTS came on */
p_cur_port_info->
cts_state = 1;
/* Generate a
Transmit Holding
Register Empty
Interrupt to allow
data to be sent */
BOUNCE_THRE;
}
else
/* CTS went off */
p_cur_port_info->
cts_state = 0;
} /* End if delta clear to send */
if (value_from_port & 0x04)
{ /* Change in Ring Indicator state */
if (IS_RING(value_from_port))
{ /* Ringing in */
/* Put ring indication
into circular buffer
*/
cur_char =
RING_INDICATION;
goto add_char_to_rx_buf;
}
} /* End if delta ring indicator */
break;
/* Unkown interrupt */
default : break;
} /* End switch on type of
interrupt */
} /* end interrupt pending */
p_cur_port_info++; /* Point at next port */
} /* End loop through all ports */
} while (interrupts_processed == 0);
/* Output non-specific End Of Interrupt to 8259
interrupt controller for IRQs 0 - 7 */
outp(R8259A_CONTROL,0x20);
/* Note - Interrupts are not re-enabled to ensure
that the IRET will be executed before the
next interrupt */
return;
}